@dxos/react-ui-table 0.6.14-main.f49f251 → 0.6.14-staging.4b6f9cf

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 (242) hide show
  1. package/dist/lib/browser/_deprecated/index.mjs +1483 -0
  2. package/dist/lib/browser/_deprecated/index.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-A5W4XWPD.mjs +18 -0
  4. package/dist/lib/browser/chunk-A5W4XWPD.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1277 -1356
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/types/index.mjs +7 -0
  9. package/dist/lib/browser/types/index.mjs.map +7 -0
  10. package/dist/lib/node/_deprecated/index.cjs +1511 -0
  11. package/dist/lib/node/_deprecated/index.cjs.map +7 -0
  12. package/dist/lib/node/chunk-32IGMRME.cjs +40 -0
  13. package/dist/lib/node/chunk-32IGMRME.cjs.map +7 -0
  14. package/dist/lib/node/index.cjs +1383 -0
  15. package/dist/lib/node/index.cjs.map +7 -0
  16. package/dist/lib/node/meta.json +1 -0
  17. package/dist/lib/node/types/index.cjs +29 -0
  18. package/dist/lib/node/types/index.cjs.map +7 -0
  19. package/dist/lib/node-esm/_deprecated/index.mjs +1485 -0
  20. package/dist/lib/node-esm/_deprecated/index.mjs.map +7 -0
  21. package/dist/lib/node-esm/chunk-DWQ4KGLD.mjs +20 -0
  22. package/dist/lib/node-esm/chunk-DWQ4KGLD.mjs.map +7 -0
  23. package/dist/lib/node-esm/index.mjs +1402 -0
  24. package/dist/lib/node-esm/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/meta.json +1 -0
  26. package/dist/lib/node-esm/types/index.mjs +8 -0
  27. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  28. package/dist/types/src/_deprecated/components/Cell/Cell.d.ts.map +1 -0
  29. package/dist/types/src/_deprecated/components/Cell/CellCombobox.d.ts.map +1 -0
  30. package/dist/types/src/_deprecated/components/Cell/index.d.ts.map +1 -0
  31. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.d.ts.map +1 -0
  32. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnMenu.stories.d.ts.map +1 -0
  33. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.d.ts.map +1 -0
  34. package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.stories.d.ts +4 -4
  35. package/dist/types/src/_deprecated/components/ColumnMenu/ColumnSettings.stories.d.ts.map +1 -0
  36. package/dist/types/src/_deprecated/components/ColumnMenu/index.d.ts.map +1 -0
  37. package/dist/types/src/_deprecated/components/Table/Table.d.ts +20 -0
  38. package/dist/types/src/_deprecated/components/Table/Table.d.ts.map +1 -0
  39. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts +116 -0
  40. package/dist/types/src/_deprecated/components/Table/Table.stories.d.ts.map +1 -0
  41. package/dist/types/src/_deprecated/components/Table/TableBody.d.ts.map +1 -0
  42. package/dist/types/src/_deprecated/components/Table/TableContext.d.ts.map +1 -0
  43. package/dist/types/src/_deprecated/components/Table/TableHead.d.ts.map +1 -0
  44. package/dist/types/src/_deprecated/components/Table/TableRootContext.d.ts.map +1 -0
  45. package/dist/types/src/_deprecated/components/Table/index.d.ts +5 -0
  46. package/dist/types/src/_deprecated/components/Table/index.d.ts.map +1 -0
  47. package/dist/types/src/_deprecated/components/Table/props.d.ts.map +1 -0
  48. package/dist/types/src/_deprecated/components/index.d.ts +4 -0
  49. package/dist/types/src/_deprecated/components/index.d.ts.map +1 -0
  50. package/dist/types/src/_deprecated/helpers.d.ts.map +1 -0
  51. package/dist/types/src/_deprecated/hooks/index.d.ts +5 -0
  52. package/dist/types/src/_deprecated/hooks/index.d.ts.map +1 -0
  53. package/dist/types/src/_deprecated/hooks/useColumnSizing.d.ts.map +1 -0
  54. package/dist/types/src/{hooks → _deprecated/hooks}/useColumnSorting.d.ts +1 -1
  55. package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts.map +1 -0
  56. package/dist/types/src/_deprecated/hooks/usePinLastRow.d.ts.map +1 -0
  57. package/dist/types/src/_deprecated/hooks/useRowSelection.d.ts.map +1 -0
  58. package/dist/types/src/_deprecated/index.d.ts +8 -0
  59. package/dist/types/src/_deprecated/index.d.ts.map +1 -0
  60. package/dist/types/src/_deprecated/schema/Schema.stories.d.ts.map +1 -0
  61. package/dist/types/src/{schema → _deprecated/schema}/column-utils.d.ts +3 -0
  62. package/dist/types/src/_deprecated/schema/column-utils.d.ts.map +1 -0
  63. package/dist/types/src/_deprecated/schema/index.d.ts.map +1 -0
  64. package/dist/types/src/{schema → _deprecated/schema}/types.d.ts +3 -2
  65. package/dist/types/src/_deprecated/schema/types.d.ts.map +1 -0
  66. package/dist/types/src/_deprecated/theme.d.ts.map +1 -0
  67. package/dist/types/src/_deprecated/translations.d.ts +21 -0
  68. package/dist/types/src/_deprecated/translations.d.ts.map +1 -0
  69. package/dist/types/src/_deprecated/types.d.ts.map +1 -0
  70. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +8 -0
  71. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -0
  72. package/dist/types/src/components/Table/ColumnSettings.d.ts +8 -0
  73. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -0
  74. package/dist/types/src/components/Table/RowActionsMenu.d.ts +8 -0
  75. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -0
  76. package/dist/types/src/components/Table/Table.d.ts +11 -14
  77. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  78. package/dist/types/src/components/Table/Table.stories.d.ts +10 -113
  79. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  80. package/dist/types/src/components/Table/index.d.ts +0 -3
  81. package/dist/types/src/components/Table/index.d.ts.map +1 -1
  82. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +17 -0
  83. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -0
  84. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +11 -0
  85. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -0
  86. package/dist/types/src/components/TableCellEditor/extension.d.ts +12 -0
  87. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +1 -0
  88. package/dist/types/src/components/TableCellEditor/index.d.ts +2 -0
  89. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -0
  90. package/dist/types/src/components/Toolbar/Toolbar.d.ts +21 -0
  91. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  92. package/dist/types/src/components/Toolbar/common.d.ts +20 -0
  93. package/dist/types/src/components/Toolbar/common.d.ts.map +1 -0
  94. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  95. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  96. package/dist/types/src/components/index.d.ts +1 -2
  97. package/dist/types/src/components/index.d.ts.map +1 -1
  98. package/dist/types/src/components/testing.d.ts +97 -0
  99. package/dist/types/src/components/testing.d.ts.map +1 -0
  100. package/dist/types/src/hooks/index.d.ts +1 -4
  101. package/dist/types/src/hooks/index.d.ts.map +1 -1
  102. package/dist/types/src/hooks/useTableModel.d.ts +15 -0
  103. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -0
  104. package/dist/types/src/index.d.ts +3 -4
  105. package/dist/types/src/index.d.ts.map +1 -1
  106. package/dist/types/src/model/index.d.ts +3 -0
  107. package/dist/types/src/model/index.d.ts.map +1 -0
  108. package/dist/types/src/model/modal-controller.d.ts +29 -0
  109. package/dist/types/src/model/modal-controller.d.ts.map +1 -0
  110. package/dist/types/src/model/selection-model.d.ts +22 -0
  111. package/dist/types/src/model/selection-model.d.ts.map +1 -0
  112. package/dist/types/src/model/table-model.d.ts +93 -0
  113. package/dist/types/src/model/table-model.d.ts.map +1 -0
  114. package/dist/types/src/model/table-model.test.d.ts +2 -0
  115. package/dist/types/src/model/table-model.test.d.ts.map +1 -0
  116. package/dist/types/src/translations.d.ts +23 -16
  117. package/dist/types/src/translations.d.ts.map +1 -1
  118. package/dist/types/src/types/index.d.ts +2 -0
  119. package/dist/types/src/types/index.d.ts.map +1 -0
  120. package/dist/types/src/types/table.d.ts +106 -0
  121. package/dist/types/src/types/table.d.ts.map +1 -0
  122. package/dist/types/src/util/grid.d.ts +14 -0
  123. package/dist/types/src/util/grid.d.ts.map +1 -0
  124. package/dist/types/src/util/index.d.ts +5 -0
  125. package/dist/types/src/util/index.d.ts.map +1 -0
  126. package/dist/types/src/util/signals.d.ts +6 -0
  127. package/dist/types/src/util/signals.d.ts.map +1 -0
  128. package/dist/types/src/util/table-buttons.d.ts +24 -0
  129. package/dist/types/src/util/table-buttons.d.ts.map +1 -0
  130. package/dist/types/src/util/table-controls.d.ts +21 -0
  131. package/dist/types/src/util/table-controls.d.ts.map +1 -0
  132. package/dist/types/src/util/table.d.ts +8 -0
  133. package/dist/types/src/util/table.d.ts.map +1 -0
  134. package/package.json +56 -22
  135. package/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.stories.tsx +4 -4
  136. package/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.stories.tsx +9 -9
  137. package/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.tsx +3 -3
  138. package/src/_deprecated/components/Table/Table.stories.tsx +508 -0
  139. package/src/_deprecated/components/Table/Table.tsx +301 -0
  140. package/src/{components → _deprecated/components}/Table/TableHead.tsx +3 -1
  141. package/src/_deprecated/components/Table/index.ts +8 -0
  142. package/src/_deprecated/components/index.ts +7 -0
  143. package/src/{helpers.tsx → _deprecated/helpers.tsx} +4 -3
  144. package/src/_deprecated/hooks/index.ts +8 -0
  145. package/src/_deprecated/index.ts +12 -0
  146. package/src/_deprecated/schema/column-utils.ts +54 -0
  147. package/src/{schema → _deprecated/schema}/types.ts +3 -2
  148. package/src/_deprecated/translations.ts +26 -0
  149. package/src/components/Table/ColumnActionsMenu.tsx +60 -0
  150. package/src/components/Table/ColumnSettings.tsx +76 -0
  151. package/src/components/Table/RowActionsMenu.tsx +36 -0
  152. package/src/components/Table/Table.stories.tsx +197 -467
  153. package/src/components/Table/Table.tsx +174 -257
  154. package/src/components/Table/index.ts +1 -4
  155. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +114 -0
  156. package/src/components/TableCellEditor/TableCellEditor.tsx +155 -0
  157. package/src/components/TableCellEditor/extension.ts +62 -0
  158. package/src/components/TableCellEditor/index.ts +5 -0
  159. package/src/components/Toolbar/Toolbar.tsx +86 -0
  160. package/src/components/Toolbar/common.tsx +72 -0
  161. package/src/components/Toolbar/index.ts +5 -0
  162. package/src/components/index.ts +2 -3
  163. package/src/components/testing.ts +114 -0
  164. package/src/hooks/index.ts +1 -4
  165. package/src/hooks/useTableModel.ts +52 -0
  166. package/src/index.ts +5 -6
  167. package/src/model/index.ts +6 -0
  168. package/src/model/modal-controller.ts +83 -0
  169. package/src/model/selection-model.ts +99 -0
  170. package/src/model/table-model.test.ts +182 -0
  171. package/src/model/table-model.ts +565 -0
  172. package/src/translations.ts +20 -13
  173. package/src/types/index.ts +5 -0
  174. package/src/types/table.ts +13 -0
  175. package/src/util/grid.ts +23 -0
  176. package/src/util/index.ts +8 -0
  177. package/src/util/signals.ts +9 -0
  178. package/src/util/table-buttons.ts +48 -0
  179. package/src/util/table-controls.ts +27 -0
  180. package/src/util/table.ts +77 -0
  181. package/dist/types/src/components/Cell/Cell.d.ts.map +0 -1
  182. package/dist/types/src/components/Cell/CellCombobox.d.ts.map +0 -1
  183. package/dist/types/src/components/Cell/index.d.ts.map +0 -1
  184. package/dist/types/src/components/ColumnMenu/ColumnMenu.d.ts.map +0 -1
  185. package/dist/types/src/components/ColumnMenu/ColumnMenu.stories.d.ts.map +0 -1
  186. package/dist/types/src/components/ColumnMenu/ColumnSettings.d.ts.map +0 -1
  187. package/dist/types/src/components/ColumnMenu/ColumnSettings.stories.d.ts.map +0 -1
  188. package/dist/types/src/components/ColumnMenu/index.d.ts.map +0 -1
  189. package/dist/types/src/components/Table/TableBody.d.ts.map +0 -1
  190. package/dist/types/src/components/Table/TableContext.d.ts.map +0 -1
  191. package/dist/types/src/components/Table/TableHead.d.ts.map +0 -1
  192. package/dist/types/src/components/Table/TableRootContext.d.ts.map +0 -1
  193. package/dist/types/src/components/Table/props.d.ts.map +0 -1
  194. package/dist/types/src/helpers.d.ts.map +0 -1
  195. package/dist/types/src/hooks/useColumnSizing.d.ts.map +0 -1
  196. package/dist/types/src/hooks/useColumnSorting.d.ts.map +0 -1
  197. package/dist/types/src/hooks/usePinLastRow.d.ts.map +0 -1
  198. package/dist/types/src/hooks/useRowSelection.d.ts.map +0 -1
  199. package/dist/types/src/schema/Schema.stories.d.ts.map +0 -1
  200. package/dist/types/src/schema/column-utils.d.ts.map +0 -1
  201. package/dist/types/src/schema/index.d.ts.map +0 -1
  202. package/dist/types/src/schema/types.d.ts.map +0 -1
  203. package/dist/types/src/theme.d.ts.map +0 -1
  204. package/dist/types/src/types.d.ts.map +0 -1
  205. package/src/schema/column-utils.ts +0 -48
  206. /package/dist/types/src/{components → _deprecated/components}/Cell/Cell.d.ts +0 -0
  207. /package/dist/types/src/{components → _deprecated/components}/Cell/CellCombobox.d.ts +0 -0
  208. /package/dist/types/src/{components → _deprecated/components}/Cell/index.d.ts +0 -0
  209. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.d.ts +0 -0
  210. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.stories.d.ts +0 -0
  211. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/ColumnSettings.d.ts +0 -0
  212. /package/dist/types/src/{components → _deprecated/components}/ColumnMenu/index.d.ts +0 -0
  213. /package/dist/types/src/{components → _deprecated/components}/Table/TableBody.d.ts +0 -0
  214. /package/dist/types/src/{components → _deprecated/components}/Table/TableContext.d.ts +0 -0
  215. /package/dist/types/src/{components → _deprecated/components}/Table/TableHead.d.ts +0 -0
  216. /package/dist/types/src/{components → _deprecated/components}/Table/TableRootContext.d.ts +0 -0
  217. /package/dist/types/src/{components → _deprecated/components}/Table/props.d.ts +0 -0
  218. /package/dist/types/src/{helpers.d.ts → _deprecated/helpers.d.ts} +0 -0
  219. /package/dist/types/src/{hooks → _deprecated/hooks}/useColumnSizing.d.ts +0 -0
  220. /package/dist/types/src/{hooks → _deprecated/hooks}/usePinLastRow.d.ts +0 -0
  221. /package/dist/types/src/{hooks → _deprecated/hooks}/useRowSelection.d.ts +0 -0
  222. /package/dist/types/src/{schema → _deprecated/schema}/Schema.stories.d.ts +0 -0
  223. /package/dist/types/src/{schema → _deprecated/schema}/index.d.ts +0 -0
  224. /package/dist/types/src/{theme.d.ts → _deprecated/theme.d.ts} +0 -0
  225. /package/dist/types/src/{types.d.ts → _deprecated/types.d.ts} +0 -0
  226. /package/src/{components → _deprecated/components}/Cell/Cell.tsx +0 -0
  227. /package/src/{components → _deprecated/components}/Cell/CellCombobox.tsx +0 -0
  228. /package/src/{components → _deprecated/components}/Cell/index.ts +0 -0
  229. /package/src/{components → _deprecated/components}/ColumnMenu/ColumnMenu.tsx +0 -0
  230. /package/src/{components → _deprecated/components}/ColumnMenu/index.ts +0 -0
  231. /package/src/{components → _deprecated/components}/Table/TableBody.tsx +0 -0
  232. /package/src/{components → _deprecated/components}/Table/TableContext.tsx +0 -0
  233. /package/src/{components → _deprecated/components}/Table/TableRootContext.ts +0 -0
  234. /package/src/{components → _deprecated/components}/Table/props.ts +0 -0
  235. /package/src/{hooks → _deprecated/hooks}/useColumnSizing.ts +0 -0
  236. /package/src/{hooks → _deprecated/hooks}/useColumnSorting.ts +0 -0
  237. /package/src/{hooks → _deprecated/hooks}/usePinLastRow.ts +0 -0
  238. /package/src/{hooks → _deprecated/hooks}/useRowSelection.ts +0 -0
  239. /package/src/{schema → _deprecated/schema}/Schema.stories.tsx +0 -0
  240. /package/src/{schema → _deprecated/schema}/index.ts +0 -0
  241. /package/src/{theme.ts → _deprecated/theme.ts} +0 -0
  242. /package/src/{types.ts → _deprecated/types.ts} +0 -0
@@ -1,1480 +1,1401 @@
1
+ import {
2
+ TableType
3
+ } from "./chunk-A5W4XWPD.mjs";
4
+
1
5
  // packages/ui/react-ui-table/src/translations.ts
2
6
  var translationKey = "table";
3
7
  var translations_default = [
4
8
  {
5
9
  "en-US": {
6
10
  [translationKey]: {
7
- "no selection label": "\xA0",
8
- "number column type label": "Number",
9
- "boolean column type label": "Boolean",
10
- "date column type label": "Date",
11
- "string column type label": "Text",
12
- "ref column type label": "Reference",
13
- "digits label": "Decimal places",
14
- "save label": "Save",
15
- "delete label": "Delete",
16
- "column label label": "Label",
17
- "property key label": "Property",
18
- "column type label": "Type"
11
+ "object placeholder": "New table",
12
+ "create object label": "Create table",
13
+ "table name placeholder": "Table name",
14
+ "settings title": "Table settings",
15
+ "table schema label": "Schema",
16
+ "new schema": "New schema",
17
+ "continue label": "Continue",
18
+ "create stack section label": "Create table",
19
+ "add row": "Add row",
20
+ "create comment": "Create thread",
21
+ "column action sort descending": "Sort Descending",
22
+ "column action sort ascending": "Sort Ascending",
23
+ "column action clear sorting": "Clear Sorting",
24
+ "column action settings": "Column Settings",
25
+ "column action delete": "Delete Column",
26
+ "delete row label": "Delete row",
27
+ "bulk delete row label": "Delete selected rows",
28
+ "column deleted label": "Column deleted",
29
+ "new column button label": "Create column"
19
30
  }
20
31
  }
21
32
  }
22
33
  ];
23
34
 
24
- // packages/ui/react-ui-table/src/components/Cell/CellCombobox.tsx
25
- import { CaretDown } from "@phosphor-icons/react";
26
- import React, { useCallback, useState } from "react";
27
- import { Popover, useTranslation } from "@dxos/react-ui";
28
- import { PopoverCombobox } from "@dxos/react-ui-searchlist";
29
- import { descriptionText, getSize, mx, staticPlaceholderText } from "@dxos/react-ui-theme";
30
- var initialItems = (model, value) => value ? {
31
- [model.getId(value)]: {
32
- label: model.getText(value),
33
- data: value
34
- }
35
- } : {};
36
- var CellCombobox = ({ model, value, onValueChange }) => {
35
+ // packages/ui/react-ui-table/src/components/Table/Table.tsx
36
+ import React5, { forwardRef, useCallback as useCallback3, useImperativeHandle, useState as useState2 } from "react";
37
+ import { getValue } from "@dxos/echo-schema";
38
+ import { invariant as invariant2 } from "@dxos/invariant";
39
+ import { Filter, getSpace as getSpace2, fullyQualifiedId } from "@dxos/react-client/echo";
40
+ import { useAttention } from "@dxos/react-ui-attention";
41
+ import { Grid, closestCell } from "@dxos/react-ui-grid";
42
+ import { StackItem } from "@dxos/react-ui-stack";
43
+ import { mx } from "@dxos/react-ui-theme";
44
+ import { isNotFalsy } from "@dxos/util";
45
+
46
+ // packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
47
+ import React from "react";
48
+ import { DropdownMenu, useTranslation } from "@dxos/react-ui";
49
+ var ColumnActionsMenu = ({ model }) => {
37
50
  const { t } = useTranslation(translationKey);
38
- const [items, setItems] = useState(initialItems(model, value));
39
- const [loading, setLoading] = useState(false);
40
- const [searchInputValue, setSearchInputValue] = useState("");
41
- const handleSearchInputValueChange = async (text) => {
42
- setSearchInputValue(text ?? "");
43
- setLoading(true);
44
- const items2 = await model.query(text);
45
- setItems(items2.reduce((acc, item) => {
46
- acc[model.getId(item)] = {
47
- label: model.getText(item),
48
- data: item
49
- };
50
- return acc;
51
- }, initialItems(model, value)));
52
- setLoading(false);
53
- };
54
- const handleValueChange = useCallback((id) => {
55
- onValueChange(items[id]?.data);
56
- }, [
57
- items,
58
- onValueChange
59
- ]);
60
- return /* @__PURE__ */ React.createElement(PopoverCombobox.Root, {
61
- placeholder: t("no selection label")
62
- }, /* @__PURE__ */ React.createElement(PopoverCombobox.Trigger, {
63
- variant: "ghost",
64
- classNames: "is-full rounded-none ring-inset"
65
- }, value ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
66
- className: mx("font-normal text-start text-baseText flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
67
- }, model.getText(value)), /* @__PURE__ */ React.createElement(CaretDown, {
68
- weight: "bold",
69
- className: getSize(3)
70
- })) : null), /* @__PURE__ */ React.createElement(PopoverCombobox.Content, {
71
- shouldFilter: false,
72
- classNames: "is-[--radix-popover-trigger-width]"
73
- }, /* @__PURE__ */ React.createElement(PopoverCombobox.Input, {
74
- value: searchInputValue,
75
- onValueChange: handleSearchInputValueChange
76
- }), /* @__PURE__ */ React.createElement(PopoverCombobox.List, null, searchInputValue.length < 1 ? /* @__PURE__ */ React.createElement("p", {
77
- className: mx("text-center", descriptionText)
78
- }, "Start typing to search") : loading ? /* @__PURE__ */ React.createElement("p", {
79
- className: mx("text-center", descriptionText)
80
- }, "Searching\u2026") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(PopoverCombobox.Empty, {
81
- classNames: [
82
- "text-center",
83
- descriptionText
84
- ]
85
- }, "No results"), Object.entries(items).map(([id, { label }]) => /* @__PURE__ */ React.createElement(PopoverCombobox.Item, {
86
- key: id,
87
- value: id,
88
- onSelect: handleValueChange,
89
- classNames: "truncate"
90
- }, label)))), /* @__PURE__ */ React.createElement(Popover.Arrow, null)));
51
+ const state = model?.modalController.state.value;
52
+ if (!model || state?.type !== "column") {
53
+ return null;
54
+ }
55
+ const currentSort = model.sorting;
56
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
57
+ return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
58
+ modal: false,
59
+ open: state?.type === "column",
60
+ onOpenChange: model.modalController.close
61
+ }, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
62
+ virtualRef: model.modalController.trigger
63
+ }), /* @__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, {
64
+ onClick: () => model.setSort(state.fieldId, "desc")
65
+ }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
66
+ onClick: () => model.setSort(state.fieldId, "asc")
67
+ }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
68
+ onClick: () => model.clearSort()
69
+ }, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
70
+ onClick: () => model.deleteColumn(state.fieldId)
71
+ }, t("column action delete")), /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
72
+ onClick: () => model.modalController.openColumnSettings()
73
+ }, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
91
74
  };
92
75
 
93
- // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
94
- import { X, GearSix, CaretDown as CaretDown2, ArrowDown, ArrowUp, ArrowRight, ArrowLeft } from "@phosphor-icons/react";
95
- import React4, { useRef as useRef2, useState as useState6, useCallback as useCallback5 } from "react";
96
- import { Button as Button2, Popover as Popover2, DropdownMenu } from "@dxos/react-ui";
97
- import { getSize as getSize2, mx as mx2 } from "@dxos/react-ui-theme";
98
-
99
- // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnSettings.tsx
100
- import React2, { useRef, useState as useState2 } from "react";
101
- import { Button, Input, Select, useTranslation as useTranslation2 } from "@dxos/react-ui";
102
- import { FieldValueTypes } from "@dxos/schema";
103
- import { safeParseInt } from "@dxos/util";
104
- var ColumnSettings = ({ column, tableDef, tablesToReference, onUpdate, onDelete, onClose }) => {
105
- const { t } = useTranslation2(translationKey);
106
- const propRef = useRef(null);
107
- const [formState, setFormState] = useState2({
108
- prop: column.id,
109
- refTable: column.refTable,
110
- refProp: column.refProp,
111
- type: String(column.type),
112
- label: column.label,
113
- digits: String(column.digits ?? "0")
114
- });
115
- const handleSave = () => {
116
- const { prop, refTable, refProp, type, label, digits } = formState;
117
- if (!prop.length || !prop.match(/^[a-zA-Z_].+/i)) {
118
- propRef.current?.focus();
119
- return;
76
+ // packages/ui/react-ui-table/src/components/Table/ColumnSettings.tsx
77
+ import React2, { useCallback, useEffect, useMemo, useState } from "react";
78
+ import { getSpace } from "@dxos/react-client/echo";
79
+ import { DropdownMenu as DropdownMenu2 } from "@dxos/react-ui";
80
+ import { FieldEditor } from "@dxos/react-ui-data";
81
+ var ColumnSettings = ({ model }) => {
82
+ const [newField, setNewField] = useState();
83
+ const state = model?.modalController.state.value;
84
+ const space = getSpace(model?.table);
85
+ useEffect(() => {
86
+ if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
87
+ setNewField(model.projection.createFieldProjection());
88
+ } else {
89
+ setNewField(void 0);
120
90
  }
121
- const current = tableDef.columns.find((c) => c.id !== column.id && c.id === prop);
122
- if (current) {
123
- if (current.type !== "ref") {
124
- propRef.current?.focus();
125
- return;
91
+ }, [
92
+ model?.projection,
93
+ state
94
+ ]);
95
+ const existingField = useMemo(() => {
96
+ if (state?.type === "columnSettings") {
97
+ const { mode } = state;
98
+ if (mode.type === "edit") {
99
+ return model?.table?.view?.fields.find((f) => f.id === mode.fieldId);
126
100
  }
127
101
  }
128
- onUpdate?.(column.id, {
129
- id: prop,
130
- prop,
131
- label,
132
- type,
133
- refTable,
134
- refProp,
135
- digits: safeParseInt(digits)
136
- });
137
- onClose?.();
138
- };
139
- const handleDelete = () => {
140
- onDelete?.(column.id);
141
- onClose?.();
142
- };
143
- return /* @__PURE__ */ React2.createElement("div", {
144
- className: "flex flex-col w-full gap-4"
145
- }, /* @__PURE__ */ React2.createElement("div", {
146
- className: "flex flex-col gap-2"
147
- }, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, t("column label label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
148
- placeholder: "Column label",
149
- value: formState.label ?? "",
150
- onChange: (event) => setFormState((prevState) => ({
151
- ...prevState,
152
- label: event.target.value
153
- })),
154
- autoFocus: true,
155
- "data-testid": "table.column-settings.label"
156
- })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, t("property key label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
157
- ref: propRef,
158
- placeholder: "Property key",
159
- value: formState.prop ?? "",
160
- onChange: (event) => setFormState((prevState) => ({
161
- ...prevState,
162
- prop: event.target.value.replace(/[^\w_]/g, "")
163
- }))
164
- })), /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, t("column type label")), /* @__PURE__ */ React2.createElement(Select.Root, {
165
- value: formState.type,
166
- onValueChange: (value) => setFormState((prevState) => ({
167
- ...prevState,
168
- type: value
169
- }))
170
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
171
- classNames: "is-full",
172
- placeholder: "Type"
173
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, FieldValueTypes.map((type) => /* @__PURE__ */ React2.createElement(Select.Option, {
174
- key: type,
175
- value: type
176
- }, t(`${type} column type label`)))))))), formState.type === "number" && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, t("digits label")), /* @__PURE__ */ React2.createElement(Input.TextInput, {
177
- value: formState.digits ?? "",
178
- onChange: (event) => setFormState((prevState) => ({
179
- ...prevState,
180
- digits: event.target.value
181
- }))
182
- })), formState.type === "ref" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, "Table"), /* @__PURE__ */ React2.createElement(Select.Root, {
183
- value: formState.refTable,
184
- onValueChange: (value) => setFormState((prevState) => ({
185
- ...prevState,
186
- refTable: value
187
- }))
188
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
189
- placeholder: "Table",
190
- classNames: "is-full"
191
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tablesToReference.filter((t2) => t2.id !== tableDef.id).map(({ id, name }) => /* @__PURE__ */ React2.createElement(Select.Option, {
192
- key: id,
193
- value: id
194
- }, name ?? id))))))), formState.refTable && /* @__PURE__ */ React2.createElement(Input.Root, null, /* @__PURE__ */ React2.createElement(Input.Label, null, "Table property"), /* @__PURE__ */ React2.createElement(Select.Root, {
195
- value: formState.refProp,
196
- onValueChange: (value) => setFormState((prevState) => ({
197
- ...prevState,
198
- refProp: value
199
- }))
200
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
201
- placeholder: "Property"
202
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, tablesToReference.find((tableDef2) => tableDef2.id === formState.refTable)?.columns.map(({ id, label }) => /* @__PURE__ */ React2.createElement(Select.Option, {
203
- key: id,
204
- value: id
205
- }, label ?? id))))))))), /* @__PURE__ */ React2.createElement("div", null, /* @__PURE__ */ React2.createElement("div", {
206
- className: "flex flex-row justify-end gap-1"
207
- }, /* @__PURE__ */ React2.createElement(Button, {
208
- onClick: handleDelete,
209
- "data-testid": "table.column-settings.delete"
210
- }, t("delete label")), /* @__PURE__ */ React2.createElement(Button, {
211
- variant: "primary",
212
- onClick: handleSave,
213
- "data-testid": "table.column-settings.save"
214
- }, t("save label")))));
215
- };
216
-
217
- // packages/ui/react-ui-table/src/hooks/useColumnSizing.ts
218
- import { useCallback as useCallback2, useEffect, useState as useState3 } from "react";
219
- import { useOnTransition } from "@dxos/react-ui";
220
- var useColumnResizing = ({ columns, onColumnResize }) => {
221
- const [columnsInitialised, setColumnsInitialised] = useState3(false);
222
- const [columnSizing, setColumnSizing] = useState3({});
223
- useEffect(() => {
224
- if (columnsInitialised) {
225
- return;
226
- }
227
- setColumnSizing(columns.filter((column) => !!column.size && column.prop !== void 0).reduce((state, column) => {
228
- state[column.prop] = column.size;
229
- return state;
230
- }, {}));
231
- setColumnsInitialised(true);
102
+ return void 0;
232
103
  }, [
233
- columns,
234
- setColumnSizing
104
+ model?.table?.view?.fields,
105
+ state
235
106
  ]);
236
- const [columnSizingInfo, setColumnSizingInfo] = useState3({});
237
- const notifyColumnResize = useCallback2(() => onColumnResize?.(columnSizing), [
238
- onColumnResize,
239
- columnSizing
107
+ const field = existingField ?? newField;
108
+ const handleClose = useCallback(() => {
109
+ model?.modalController.close();
110
+ }, [
111
+ model?.modalController
240
112
  ]);
241
- useOnTransition(columnSizingInfo.isResizingColumn, (v) => typeof v === "string", false, notifyColumnResize);
242
- return {
243
- columnSizing,
244
- columnSizingInfo,
245
- setColumnSizing,
246
- setColumnSizingInfo
247
- };
113
+ const handleCancel = useCallback(() => {
114
+ if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
115
+ model?.projection?.deleteFieldProjection(newField.id);
116
+ }
117
+ }, [
118
+ model?.projection,
119
+ state,
120
+ newField
121
+ ]);
122
+ if (!model?.table?.view || !model.projection || !field) {
123
+ return null;
124
+ }
125
+ return /* @__PURE__ */ React2.createElement(DropdownMenu2.Root, {
126
+ modal: false,
127
+ open: state?.type === "columnSettings"
128
+ }, /* @__PURE__ */ React2.createElement(DropdownMenu2.VirtualTrigger, {
129
+ virtualRef: model.modalController.trigger
130
+ }), /* @__PURE__ */ React2.createElement(DropdownMenu2.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu2.Content, {
131
+ classNames: "md:is-64"
132
+ }, /* @__PURE__ */ React2.createElement(DropdownMenu2.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
133
+ view: model.table.view,
134
+ projection: model.projection,
135
+ field,
136
+ registry: space?.db.schemaRegistry,
137
+ onClose: handleClose,
138
+ onCancel: handleCancel
139
+ })), /* @__PURE__ */ React2.createElement(DropdownMenu2.Arrow, null))));
248
140
  };
249
141
 
250
- // packages/ui/react-ui-table/src/hooks/useColumnSorting.ts
251
- import { useState as useState4 } from "react";
252
-
253
- // packages/ui/react-ui-table/src/components/Table/TableContext.tsx
254
- import React3, { useContext, createContext } from "react";
255
- import { raise } from "@dxos/debug";
256
- var TABLE_NAME = "Table";
257
- var TableContext = /* @__PURE__ */ createContext(void 0);
258
- var TableProvider = ({ children, ...value }) => {
259
- return /* @__PURE__ */ React3.createElement(TableContext.Provider, {
260
- value
261
- }, children);
262
- };
263
- var useTableContext = () => {
264
- return useContext(TableContext) ?? raise(new Error("Missing TableContext"));
142
+ // packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
143
+ import React3 from "react";
144
+ import { DropdownMenu as DropdownMenu3, useTranslation as useTranslation2 } from "@dxos/react-ui";
145
+ var RowActionsMenu = ({ model }) => {
146
+ const { t } = useTranslation2(translationKey);
147
+ const state = model.modalController.state.value;
148
+ const hasSelection = model.selection.hasSelection.value;
149
+ if (state?.type !== "row") {
150
+ return null;
151
+ }
152
+ return /* @__PURE__ */ React3.createElement(DropdownMenu3.Root, {
153
+ modal: false,
154
+ open: true,
155
+ onOpenChange: model.modalController.close
156
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu3.VirtualTrigger, {
157
+ virtualRef: model.modalController.trigger
158
+ }), /* @__PURE__ */ React3.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React3.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React3.createElement(DropdownMenu3.Item, {
159
+ onClick: () => model.deleteRow(state.rowIndex)
160
+ }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React3.createElement(DropdownMenu3.Arrow, null)));
265
161
  };
266
162
 
267
- // packages/ui/react-ui-table/src/hooks/useColumnSorting.ts
268
- var useColumnSorting = () => {
269
- const [columnSorting, setColumnSorting] = useState4([]);
270
- const sortColumn = (columnId, sortDirection) => {
271
- setColumnSorting([
272
- {
273
- id: columnId,
274
- desc: sortDirection === "desc"
163
+ // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
164
+ import React4, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
165
+ import { FormatEnum as FormatEnum2 } from "@dxos/echo-schema";
166
+ import { invariant } from "@dxos/invariant";
167
+ import { editorKeys, GridCellEditor, useGridContext } from "@dxos/react-ui-grid";
168
+
169
+ // packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
170
+ import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
171
+ import { EditorView } from "@codemirror/view";
172
+ var completion = ({ onQuery, onMatch }) => {
173
+ return [
174
+ EditorView.theme({
175
+ ".cm-completionDialog": {
176
+ width: "var(--dx-gridCellWidth)"
275
177
  }
276
- ]);
277
- };
278
- const clearColumnSorting = () => {
279
- setColumnSorting([]);
280
- };
281
- return {
282
- sorting: columnSorting,
283
- sortColumn,
284
- clearColumnSorting
285
- };
178
+ }),
179
+ autocompletion({
180
+ icons: false,
181
+ activateOnTyping: true,
182
+ override: [
183
+ async (context) => {
184
+ const text = context.state.doc.toString();
185
+ return {
186
+ from: 0,
187
+ options: await onQuery(text)
188
+ };
189
+ }
190
+ ],
191
+ // TODO(burdon): Consts from grid (to line-up with grid).
192
+ tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
193
+ optionClass: () => "flex h-[33px] items-center"
194
+ }),
195
+ // Check for accepted completion metadata in the transaction.
196
+ EditorView.updateListener.of((update) => {
197
+ update.transactions.forEach((tr) => {
198
+ const completion2 = tr.annotation(pickedCompletion);
199
+ if (completion2) {
200
+ onMatch(completion2.data);
201
+ }
202
+ });
203
+ })
204
+ ];
286
205
  };
287
- var useSortColumn = (column) => {
288
- const { sorting, sortColumn, clearColumnSorting } = useTableContext();
289
- const [initialSortDirection, setInitialSortDirection] = useState4();
290
- const columnSort = sorting.find((s) => s.id === column.id);
291
- const sortDirection = columnSort ? columnSort.desc ? "desc" : "asc" : void 0;
292
- const canSort = column.getCanSort();
293
- const updateColumnSort = (direction) => {
294
- sortColumn(column.id, direction);
295
- };
296
- const onToggleSort = () => {
297
- if (sortDirection === void 0) {
298
- return;
299
- }
300
- if (sortDirection === initialSortDirection) {
301
- updateColumnSort(initialSortDirection === "asc" ? "desc" : "asc");
302
- } else {
303
- clearColumnSorting();
304
- }
305
- };
306
- const onSelectSort = (direction) => {
307
- clearColumnSorting();
308
- setInitialSortDirection(direction);
309
- updateColumnSort(direction);
310
- };
311
- const onClearSort = () => {
312
- clearColumnSorting();
313
- };
206
+
207
+ // packages/ui/react-ui-table/src/util/grid.ts
208
+ var fromGridCell = ({ col, row }) => {
209
+ return `${col},${row}`;
210
+ };
211
+ var toGridCell = (cell) => {
212
+ const [col, row] = cell.split(",").map(Number);
314
213
  return {
315
- canSort,
316
- sortDirection,
317
- onSelectSort,
318
- onToggleSort,
319
- onClearSort
214
+ row,
215
+ col
320
216
  };
321
217
  };
322
218
 
323
- // packages/ui/react-ui-table/src/hooks/usePinLastRow.ts
324
- import { useCallback as useCallback3, useEffect as useEffect2, useState as useState5 } from "react";
325
- var usePinLastRow = (pinLastRow, table, data) => {
326
- const [pinnedRowKey, setPinnedRowKey] = useState5();
327
- const pinRow = useCallback3((rowToPin) => {
328
- table.resetRowPinning();
329
- rowToPin.pin("bottom");
330
- setPinnedRowKey(rowToPin.id);
331
- }, [
332
- table
333
- ]);
334
- const clearRowPinning = useCallback3(() => {
335
- table.resetRowPinning();
336
- setPinnedRowKey(void 0);
337
- }, [
219
+ // packages/ui/react-ui-table/src/util/signals.ts
220
+ var touch = (value) => value;
221
+
222
+ // packages/ui/react-ui-table/src/util/table.ts
223
+ import { AST, Format, FormatEnum, S, TypedObject, TypeEnum } from "@dxos/echo-schema";
224
+ import { log } from "@dxos/log";
225
+ import { PublicKey } from "@dxos/react-client";
226
+ import { create } from "@dxos/react-client/echo";
227
+ import { createFieldId, createView, ViewProjection } from "@dxos/schema";
228
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
229
+ var initializeTable = ({ space, table }) => {
230
+ log.info("initializeTable", {
338
231
  table
339
- ]);
340
- const pinLastRowCallback = useCallback3(() => {
341
- const rows = table.getRowModel().rows;
342
- if (rows.length === 0) {
343
- return clearRowPinning();
232
+ }, {
233
+ F: __dxlog_file,
234
+ L: 26,
235
+ S: void 0,
236
+ C: (f, a) => f(...a)
237
+ });
238
+ const ContactSchema = TypedObject({
239
+ typename: `example.com/type/${PublicKey.random().truncate()}`,
240
+ version: "0.1.0"
241
+ })({
242
+ name: S.optional(S.String).annotations({
243
+ [AST.TitleAnnotationId]: "Name"
244
+ }),
245
+ email: S.optional(Format.Email),
246
+ salary: S.optional(Format.Currency()).annotations({
247
+ [AST.TitleAnnotationId]: "Salary"
248
+ })
249
+ });
250
+ const contactSchema = space.db.schemaRegistry.addSchema(ContactSchema);
251
+ table.view = createView({
252
+ name: "Test",
253
+ typename: contactSchema.typename,
254
+ jsonSchema: contactSchema.jsonSchema,
255
+ fields: [
256
+ "name",
257
+ "email",
258
+ "salary"
259
+ ]
260
+ });
261
+ const projection = new ViewProjection(contactSchema, table.view);
262
+ projection.setFieldProjection({
263
+ field: {
264
+ id: table.view.fields[2].id,
265
+ path: "salary",
266
+ size: 150
267
+ }
268
+ });
269
+ projection.setFieldProjection({
270
+ field: {
271
+ id: createFieldId(),
272
+ path: "manager",
273
+ referencePath: "name"
274
+ },
275
+ props: {
276
+ property: "manager",
277
+ type: TypeEnum.Ref,
278
+ format: FormatEnum.Ref,
279
+ referenceSchema: contactSchema.typename,
280
+ title: "Manager"
344
281
  }
345
- const lastRow = rows[rows.length - 1];
346
- if (lastRow.id === pinnedRowKey) {
282
+ });
283
+ space.db.add(create(contactSchema, {}));
284
+ return contactSchema;
285
+ };
286
+
287
+ // packages/ui/react-ui-table/src/util/table-buttons.ts
288
+ var TABLE_ATTRS = {
289
+ columnSettings: "data-table-column-settings-button",
290
+ rowMenu: "data-table-row-menu-button",
291
+ newColumn: "data-table-new-column-button"
292
+ };
293
+ var ICONS = {
294
+ columnSettings: "ph--caret-down--regular",
295
+ rowMenu: "ph--dots-three--regular",
296
+ newColumn: "ph--plus--regular"
297
+ };
298
+ var createButtonHtml = ({ button, value = "", disabled = false }) => {
299
+ const buttonClasses = "ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 inline-end-2";
300
+ return `<button class="${buttonClasses}" ${TABLE_ATTRS[button]}="${value}" ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${ICONS[button]}"/></svg></button>`;
301
+ };
302
+ var tableButtons = {
303
+ columnSettings: {
304
+ attr: TABLE_ATTRS.columnSettings,
305
+ icon: ICONS.columnSettings,
306
+ render: ({ fieldId }) => createButtonHtml({
307
+ button: "columnSettings",
308
+ value: fieldId
309
+ })
310
+ },
311
+ rowMenu: {
312
+ attr: TABLE_ATTRS.rowMenu,
313
+ icon: ICONS.rowMenu,
314
+ render: ({ rowIndex }) => createButtonHtml({
315
+ button: "rowMenu",
316
+ value: rowIndex.toString()
317
+ })
318
+ },
319
+ addColumn: {
320
+ attr: TABLE_ATTRS.newColumn,
321
+ icon: ICONS.newColumn,
322
+ render: ({ disabled } = {}) => createButtonHtml({
323
+ button: "newColumn",
324
+ disabled
325
+ })
326
+ }
327
+ };
328
+
329
+ // packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
330
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
331
+ var TableCellEditor = ({ model, onEnter, onFocus, onQuery, __gridScope }) => {
332
+ const { editing } = useGridContext("TableCellEditor", __gridScope);
333
+ const fieldProjection = useMemo2(() => {
334
+ if (!model || !editing) {
347
335
  return;
348
336
  }
349
- pinRow(lastRow);
337
+ const { col } = toGridCell(editing.index);
338
+ const field = model.projection.view.fields[col];
339
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
340
+ invariant(fieldProjection2, void 0, {
341
+ F: __dxlog_file2,
342
+ L: 49,
343
+ S: void 0,
344
+ A: [
345
+ "fieldProjection",
346
+ ""
347
+ ]
348
+ });
349
+ return fieldProjection2;
350
350
  }, [
351
- table,
352
- pinnedRowKey
351
+ model,
352
+ editing
353
353
  ]);
354
- useEffect2(() => {
355
- if (pinLastRow) {
356
- pinLastRowCallback();
354
+ const handleClose = useCallback2((value, event) => {
355
+ if (!model || !editing || !fieldProjection) {
356
+ return;
357
+ }
358
+ const cell = toGridCell(editing.index);
359
+ onEnter?.(cell);
360
+ if (event && onFocus) {
361
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
357
362
  }
358
363
  }, [
359
- data,
360
- pinLastRow,
361
- pinLastRowCallback
364
+ model,
365
+ editing,
366
+ onFocus,
367
+ onEnter,
368
+ fieldProjection,
369
+ determineNavigationAxis,
370
+ determineNavigationDelta
362
371
  ]);
363
- };
364
-
365
- // packages/ui/react-ui-table/src/hooks/useRowSelection.ts
366
- import { useControllableState } from "@radix-ui/react-use-controllable-state";
367
- import { useCallback as useCallback4 } from "react";
368
- var useRowSelection = (props) => {
369
- const [rowSelection = {}, setRowSelection] = useControllableState({
370
- prop: props.rowSelection,
371
- onChange: props.onRowSelectionChange,
372
- defaultProp: props.defaultRowSelection
373
- });
374
- const handleRowSelectionChange = useCallback4((updaterOrValue) => {
375
- const nextRowSelection = typeof updaterOrValue === "function" ? updaterOrValue(rowSelection) : updaterOrValue;
376
- if (props.rowsSelectable === "multi") {
377
- setRowSelection(nextRowSelection);
378
- } else if (props.rowsSelectable) {
379
- const nextRowSelectionKey = Object.keys(nextRowSelection).filter((id) => !rowSelection[id])[0];
380
- setRowSelection(nextRowSelectionKey ? {
381
- [nextRowSelectionKey]: true
382
- } : {});
383
- } else {
384
- setRowSelection({});
372
+ const handleBlur = useCallback2((value) => {
373
+ if (!model || !editing) {
374
+ return;
375
+ }
376
+ const cell = toGridCell(editing.index);
377
+ if (value !== void 0) {
378
+ model.setCellData(cell, value);
385
379
  }
386
380
  }, [
387
- props.rowsSelectable,
388
- setRowSelection,
389
- rowSelection
381
+ model,
382
+ editing
390
383
  ]);
391
- return {
392
- rowSelection,
393
- handleRowSelectionChange
394
- };
395
- };
396
-
397
- // packages/ui/react-ui-table/src/components/ColumnMenu/ColumnMenu.tsx
398
- var ColumnMenu = ({ column, columnOrderable, columnPosition, onColumnReorder, ...props }) => {
399
- const title = column.label?.length ? column.label : column.id;
400
- const header = props.context.header;
401
- const { canSort, sortDirection, onSelectSort, onToggleSort, onClearSort } = useSortColumn(header.column);
402
- const columnSettingsAnchorRef = useRef2(null);
403
- const [isColumnSettingsOpen, setIsColumnSettingsOpen] = useState6(false);
404
- const shouldPreventFocusOnClose = useRef2(false);
405
- const onOpenColumnSettings = useCallback5(() => {
406
- shouldPreventFocusOnClose.current = true;
407
- setIsColumnSettingsOpen(true);
384
+ const extension = useMemo2(() => {
385
+ if (!fieldProjection) {
386
+ return [];
387
+ }
388
+ const extension2 = [
389
+ editorKeys({
390
+ onClose: handleClose,
391
+ ...editing?.initialContent && {
392
+ onNav: handleClose
393
+ }
394
+ })
395
+ ];
396
+ if (onQuery) {
397
+ switch (fieldProjection.props.format) {
398
+ case FormatEnum2.Ref: {
399
+ extension2.push([
400
+ completion({
401
+ onQuery: (text) => onQuery(fieldProjection, text),
402
+ onMatch: (data) => {
403
+ if (model && editing) {
404
+ const cell = toGridCell(editing.index);
405
+ model.setCellData(cell, data);
406
+ onEnter?.(cell);
407
+ onFocus?.();
408
+ }
409
+ }
410
+ })
411
+ ]);
412
+ break;
413
+ }
414
+ }
415
+ }
416
+ return extension2;
408
417
  }, [
409
- shouldPreventFocusOnClose,
410
- setIsColumnSettingsOpen
418
+ model,
419
+ editing,
420
+ fieldProjection,
421
+ handleClose
411
422
  ]);
412
- const onDropdownCloseAutoFocus = useCallback5((event) => {
413
- if (shouldPreventFocusOnClose.current) {
414
- event.preventDefault();
415
- shouldPreventFocusOnClose.current = false;
423
+ const getCellContent = useCallback2(() => {
424
+ if (model && editing) {
425
+ const value = model.getCellData(toGridCell(editing.index));
426
+ return value !== void 0 ? String(value) : "";
416
427
  }
417
428
  }, [
418
- shouldPreventFocusOnClose
429
+ model,
430
+ editing
419
431
  ]);
420
- return /* @__PURE__ */ React4.createElement("div", {
421
- className: "flex items-center justify-between"
422
- }, /* @__PURE__ */ React4.createElement("div", {
423
- className: "flex items-center gap-1 truncate",
424
- title
425
- }, /* @__PURE__ */ React4.createElement(SortIndicator, {
426
- direction: sortDirection,
427
- onClick: onToggleSort
428
- }), /* @__PURE__ */ React4.createElement("div", {
429
- className: "truncate"
430
- }, title)), /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
431
- modal: false
432
- }, /* @__PURE__ */ React4.createElement(Popover2.Root, {
433
- open: isColumnSettingsOpen,
434
- onOpenChange: setIsColumnSettingsOpen,
435
- modal: false
436
- }, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
437
- ref: columnSettingsAnchorRef,
438
- asChild: true
439
- }, /* @__PURE__ */ React4.createElement(Popover2.Anchor, {
440
- asChild: true
441
- }, /* @__PURE__ */ React4.createElement(Button2, {
442
- variant: "ghost",
443
- "data-testid": "table.column-menu"
444
- }, /* @__PURE__ */ React4.createElement(CaretDown2, {
445
- className: getSize2(4)
446
- })))), /* @__PURE__ */ React4.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Content, {
447
- onCloseAutoFocus: onDropdownCloseAutoFocus,
448
- sideOffset: 4,
449
- collisionPadding: 8
450
- }, /* @__PURE__ */ React4.createElement(DropdownMenu.Viewport, null, canSort && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
451
- onClick: () => onSelectSort("asc")
452
- }, /* @__PURE__ */ React4.createElement("span", {
453
- className: "grow"
454
- }, "Sort ascending"), /* @__PURE__ */ React4.createElement("span", {
455
- className: "opacity-50"
456
- }, /* @__PURE__ */ React4.createElement(ArrowUp, {
457
- className: getSize2(4)
458
- }))), /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
459
- onClick: () => onSelectSort("desc")
460
- }, /* @__PURE__ */ React4.createElement("span", {
461
- className: "grow"
462
- }, "Sort descending"), /* @__PURE__ */ React4.createElement("span", {
463
- className: "opacity-50"
464
- }, /* @__PURE__ */ React4.createElement(ArrowDown, {
465
- className: getSize2(4)
466
- }))), sortDirection && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
467
- onClick: onClearSort
468
- }, /* @__PURE__ */ React4.createElement("span", {
469
- className: "grow"
470
- }, "Clear sort"), /* @__PURE__ */ React4.createElement("span", {
471
- className: "opacity-50"
472
- }, /* @__PURE__ */ React4.createElement(X, {
473
- className: getSize2(4)
474
- })))), columnOrderable && /* @__PURE__ */ React4.createElement(React4.Fragment, null, columnPosition !== "start" && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
475
- onClick: () => onColumnReorder(header.column.id, "left")
476
- }, /* @__PURE__ */ React4.createElement("span", {
477
- className: "grow"
478
- }, "Move left"), /* @__PURE__ */ React4.createElement("span", {
479
- className: "opacity-50"
480
- }, /* @__PURE__ */ React4.createElement(ArrowLeft, {
481
- className: mx2(getSize2(4))
482
- }))), columnPosition !== "end" && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
483
- onClick: () => onColumnReorder(header.column.id, "right")
484
- }, /* @__PURE__ */ React4.createElement("span", {
485
- className: "grow"
486
- }, "Move right"), /* @__PURE__ */ React4.createElement("span", {
487
- className: "opacity-50"
488
- }, /* @__PURE__ */ React4.createElement(ArrowRight, {
489
- className: mx2(getSize2(4))
490
- })))), /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
491
- onClick: onOpenColumnSettings,
492
- "data-testid": "table.open-column-settings"
493
- }, /* @__PURE__ */ React4.createElement("span", {
494
- className: "grow"
495
- }, "Column settings"), /* @__PURE__ */ React4.createElement("span", {
496
- className: "opacity-50"
497
- }, /* @__PURE__ */ React4.createElement(GearSix, {
498
- className: mx2(getSize2(4), "rotate-90")
499
- })))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))), /* @__PURE__ */ React4.createElement(Popover2.Portal, null, /* @__PURE__ */ React4.createElement(Popover2.Content, null, /* @__PURE__ */ React4.createElement(Popover2.Viewport, null, /* @__PURE__ */ React4.createElement(ColumnSettings, {
500
- ...props,
501
- column,
502
- onClose: () => setIsColumnSettingsOpen(false)
503
- })), /* @__PURE__ */ React4.createElement(Popover2.Arrow, null))))));
432
+ return /* @__PURE__ */ React4.createElement(GridCellEditor, {
433
+ extension,
434
+ getCellContent,
435
+ onBlur: handleBlur
436
+ });
504
437
  };
505
- var SortIndicator = ({ direction, onClick }) => {
506
- if (direction === void 0) {
507
- return null;
438
+ var determineNavigationAxis = ({ key }) => {
439
+ switch (key) {
440
+ case "ArrowUp":
441
+ case "ArrowDown":
442
+ case "Enter": {
443
+ return "row";
444
+ }
445
+ case "ArrowLeft":
446
+ case "ArrowRight":
447
+ case "Tab":
448
+ return "col";
508
449
  }
509
- let icon;
510
- switch (direction) {
511
- case "asc":
512
- icon = /* @__PURE__ */ React4.createElement(ArrowUp, {
513
- className: getSize2(3)
514
- });
515
- break;
516
- case "desc":
517
- icon = /* @__PURE__ */ React4.createElement(ArrowDown, {
518
- className: getSize2(3)
519
- });
520
- break;
450
+ };
451
+ var determineNavigationDelta = ({ key, shift }) => {
452
+ switch (key) {
453
+ case "ArrowUp":
454
+ case "ArrowLeft":
455
+ return -1;
456
+ case "ArrowDown":
457
+ case "ArrowRight":
458
+ return 1;
521
459
  }
522
- return /* @__PURE__ */ React4.createElement("div", {
523
- onClick,
524
- className: "flex items-center cursor-pointer"
525
- }, icon);
460
+ return shift ? -1 : 1;
526
461
  };
527
462
 
528
463
  // packages/ui/react-ui-table/src/components/Table/Table.tsx
529
- import { Slot } from "@radix-ui/react-slot";
530
- import { getCoreRowModel, getExpandedRowModel, getGroupedRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
531
- import React8, { Fragment, memo, useCallback as useCallback7, useEffect as useEffect3, useState as useState8, useContext as useContext3 } from "react";
532
- import { useDefaultValue } from "@dxos/react-ui";
533
- import { mx as mx4 } from "@dxos/react-ui-theme";
534
-
535
- // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
536
- import { useArrowNavigationGroup } from "@fluentui/react-tabster";
537
- import { flexRender } from "@tanstack/react-table";
538
- import React6, { useContext as useContext2 } from "react";
539
-
540
- // packages/ui/react-ui-table/src/components/Table/TableRootContext.ts
541
- import { useVirtualizer } from "@tanstack/react-virtual";
542
- import { createContext as createContext2, useRef as useRef3, useState as useState7 } from "react";
543
- var useTableRootContext = () => {
544
- const scrollContextRef = useRef3(null);
545
- const [tableCount, setTableCount] = useState7(0);
546
- const virtualizer = useVirtualizer({
547
- getScrollElement: () => scrollContextRef?.current ?? null,
548
- count: tableCount,
549
- overscan: 8,
550
- estimateSize: () => 40
551
- });
552
- const dispatch = (action) => {
553
- switch (action.type) {
554
- case "updateTableCount":
555
- setTableCount(action.count);
556
- break;
557
- default:
558
- break;
559
- }
560
- };
561
- return {
562
- scrollContextRef,
563
- virtualizer,
564
- dispatch
565
- };
566
- };
567
- var TableRootContext = createContext2({});
568
-
569
- // packages/ui/react-ui-table/src/theme.ts
570
- import { focusRing, ghostSelected, ghostSelectedCurrent, mx as mx3 } from "@dxos/react-ui-theme";
571
- var currentRow = "!bg-neutral-75 !dark:bg-neutral-850";
572
- var selectedRow = "!bg-primary-100 dark:!bg-primary-700";
573
- var flushPadding = "pli-0 plb-0";
574
- var textPadding = "pli-2 plb-0";
575
- var headPadding = "pli-2 plb-0";
576
- var gridCellFocusRing = "relative focus-within:outline focus-within:outline-1 outline-primary-500 outline-offset-[-1px]";
577
- var borderColors = "border-neutral-200 dark:border-neutral-700";
578
- var stickyRowColors = "bg-neutral-50 dark:bg-neutral-800";
579
- var tableRoot = ({ fullWidth }, ...etc) => mx3("table-fixed", "text-neutral-800 dark:text-neutral-200", fullWidth && "is-full", ...etc);
580
- var groupTh = (_props, ...etc) => mx3("text-start font-medium", flushPadding, ...etc);
581
- var theadRoot = ({ header, stickyHeader }, ...etc) => mx3(header ? stickyHeader && "sticky block-start-[--sticky-top] z-[1]" : "collapse", stickyRowColors, ...etc);
582
- var theadTr = (_props, ...etc) => mx3("group", ...etc);
583
- var theadTh = ({ border }, ...etc) => mx3("relative", "text-start text-xs select-none truncate", headPadding, border && borderColors, border && "border-t border-b border-l last:border-r", ...etc);
584
- var theadResizeRoot = ({ isResizing }) => {
585
- return mx3("absolute h-full w-[4px] top-0 right-0", "cursor-col-resize", "user-select-none", "touch-action-none", "pointer-coarse:bg-neutral-100 dark:pointer-coarse:bg-neutral-800", !isResizing && "group-hover:bg-neutral-100 dark:group-hover:bg-neutral-800", isResizing && "bg-primary-500");
586
- };
587
- var tbodyRoot = (_props, ...etc) => mx3(...etc);
588
- var tbodyTr = ({ canBeCurrent, isPinned }, ...etc) => mx3("group", canBeCurrent ? ghostSelectedCurrent : ghostSelected, canBeCurrent && focusRing, canBeCurrent && "cursor-pointer", isPinned && "sticky z-1 block-end-0", isPinned && stickyRowColors, ...etc);
589
- var tdRoot = ({ border, isGrid, pinned }, ...etc) => mx3("relative", "focus-within:!bg-neutral-50 dark:focus-within:!bg-neutral-900", flushPadding, border && "border-b border-l last:border-r border-neutral-200 dark:border-neutral-700", pinned && "border-t", isGrid && gridCellFocusRing, ...etc);
590
-
591
- // packages/ui/react-ui-table/src/components/Cell/Cell.tsx
592
- import { useFocusableGroup } from "@fluentui/react-tabster";
593
- import React5, { useCallback as useCallback6 } from "react";
594
- var CELL_NAME = "Cell";
595
- var FocusableCell = ({ cell, children }) => {
596
- const tableContext = useTableContext();
597
- const domAttributes = useFocusableGroup({
598
- tabBehavior: "limited"
599
- });
600
- const pinned = tableContext.table.getState().rowPinning?.bottom?.includes(cell.row.id);
601
- const className = tdRoot({
602
- ...tableContext,
603
- pinned
604
- }, cell.column.columnDef.meta?.cell?.classNames);
605
- const handleKeyDown = useCallback6(({ key, currentTarget }) => {
606
- if (key !== "Enter") {
607
- return;
608
- }
609
- const currentRow2 = currentTarget.closest("tr");
610
- if (!currentRow2) {
611
- return;
612
- }
613
- const cellIndex = Array.from(currentRow2.cells || []).indexOf(currentTarget);
614
- const nextSibling = currentRow2.nextElementSibling;
615
- if (!(nextSibling instanceof HTMLTableRowElement)) {
616
- let depth = 0;
617
- const pollForNewRow = () => {
618
- const newNextSibling = currentRow2.nextElementSibling;
619
- if (newNextSibling instanceof HTMLTableRowElement) {
620
- const nextCell = newNextSibling.cells[cellIndex];
621
- const input = nextCell.querySelector("input");
622
- if (input) {
623
- input.focus();
624
- }
625
- currentRow2.scrollIntoView({
626
- behavior: "smooth",
627
- block: "center"
628
- });
629
- } else if (depth++ < 100) {
630
- requestAnimationFrame(pollForNewRow);
631
- }
632
- };
633
- requestAnimationFrame(pollForNewRow);
634
- }
635
- }, []);
636
- return /* @__PURE__ */ React5.createElement("td", {
637
- "data-testid": "table.cell",
638
- tabIndex: 0,
639
- ...domAttributes,
640
- className,
641
- onKeyDown: handleKeyDown
642
- }, children);
643
- };
644
- var StaticCell = ({ cell, children }) => {
645
- const tableContext = useTableContext();
646
- return /* @__PURE__ */ React5.createElement("td", {
647
- "data-testid": "table.cell",
648
- className: tdRoot(tableContext, cell.column.columnDef.meta?.cell?.classNames)
649
- }, children);
464
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
465
+ 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";
466
+ 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";
467
+ var frozen = {
468
+ frozenRowsStart: 1,
469
+ frozenColsStart: 1,
470
+ frozenColsEnd: 1
650
471
  };
651
- var Cell = ({ cell, children }) => {
652
- const { isGrid } = useTableContext();
653
- const Root = isGrid ? FocusableCell : StaticCell;
654
- return /* @__PURE__ */ React5.createElement(Root, {
655
- cell
472
+ var TableRoot = ({ children }) => {
473
+ return /* @__PURE__ */ React5.createElement(StackItem.Content, {
474
+ toolbar: true,
475
+ contentSize: "intrinsic",
476
+ classNames: "relative"
656
477
  }, children);
657
478
  };
658
- Cell.displayName = CELL_NAME;
659
-
660
- // packages/ui/react-ui-table/src/components/Table/TableBody.tsx
661
- var TABLE_BODY_NAME = "TableBody";
662
- var TableBody = ({ rows }) => {
663
- const { table, keyAccessor, currentDatum, debug, expand, isGrid, onDatumClick } = useTableContext();
664
- const rowSelection = table.getState().rowSelection;
665
- const domAttributes = useArrowNavigationGroup({
666
- axis: "grid"
667
- });
668
- const canBeCurrent = !isGrid && !!onDatumClick;
669
- const { virtualizer } = useContext2(TableRootContext);
670
- return /* @__PURE__ */ React6.createElement("tbody", isGrid && domAttributes, rows.map((row) => {
671
- const isCurrent = currentDatum === row.original;
672
- const isSelected = rowSelection?.[row.id];
673
- const isPinned = row.getIsPinned();
674
- const classNames = tbodyTr({
675
- canBeCurrent,
676
- isPinned: isPinned !== false
677
- });
678
- return /* @__PURE__ */ React6.createElement("tr", {
679
- key: keyAccessor ? keyAccessor(row.original) : row.id,
680
- className: classNames,
681
- "data-index": row.index,
682
- "data-testid": "table.data-row",
683
- ref: virtualizer.measureElement,
684
- ...isCurrent && {
685
- "aria-current": "location"
686
- },
687
- ...isSelected && {
688
- "aria-selected": "true"
689
- },
690
- ...canBeCurrent && {
691
- tabIndex: 0,
692
- onClick: () => {
693
- onDatumClick(row.original);
694
- },
695
- onKeyUp: ({ key }) => {
696
- if (key === "Enter" || key === " ") {
697
- onDatumClick(row.original);
698
- }
479
+ var TableMain = /* @__PURE__ */ forwardRef(({ model }, forwardedRef) => {
480
+ const [dxGrid, setDxGrid] = useState2(null);
481
+ const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
482
+ useImperativeHandle(forwardedRef, () => {
483
+ if (!model || !dxGrid) {
484
+ return {};
485
+ }
486
+ dxGrid.getCells = model.getCells.bind(model);
487
+ return {
488
+ update: (cell) => {
489
+ if (cell) {
490
+ dxGrid.updateIfWithinBounds(cell);
491
+ } else {
492
+ dxGrid.updateCells(true);
699
493
  }
700
494
  }
701
- }, debug && /* @__PURE__ */ React6.createElement("td", null, row.id), row.getVisibleCells().map((cell) => {
702
- return /* @__PURE__ */ React6.createElement(Cell, {
703
- key: cell.id,
704
- cell
705
- }, flexRender(cell.column.columnDef.cell, {
706
- ...cell.getContext()
707
- }));
708
- }), expand && /* @__PURE__ */ React6.createElement("td", null));
709
- }));
710
- };
711
- TableBody.displayName = TABLE_BODY_NAME;
712
-
713
- // packages/ui/react-ui-table/src/components/Table/TableHead.tsx
714
- import { flexRender as flexRender2 } from "@tanstack/react-table";
715
- import React7 from "react";
716
- var TABLE_HEAD_NAME = "TableHeader";
717
- var TableHead = (_props) => {
718
- const tableContext = useTableContext();
719
- const headerGroups = tableContext.table.getHeaderGroups();
720
- return /* @__PURE__ */ React7.createElement("thead", {
721
- className: theadRoot(tableContext)
722
- }, headerGroups.map((headerGroup) => {
723
- return (
724
- // Group element to hover resize handles.
725
- /* @__PURE__ */ React7.createElement("tr", {
726
- key: headerGroup.id,
727
- className: theadTr(tableContext)
728
- }, tableContext.debug && /* @__PURE__ */ React7.createElement("th", {
729
- className: "font-mono",
730
- style: {
731
- width: 32
732
- }
733
- }, "#"), headerGroup.headers.map((header) => {
734
- const isResizing = header.column.getIsResizing();
735
- const onResize = header.getResizeHandler();
736
- const resizable = header.column.columnDef.meta?.resizable;
737
- return /* @__PURE__ */ React7.createElement("th", {
738
- key: header.id,
739
- style: {
740
- width: header.getSize()
741
- },
742
- className: theadTh(tableContext, header.column.columnDef.meta?.header?.classNames),
743
- "data-testid": "table.header-cell"
744
- }, !header || header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext()), resizable && /* @__PURE__ */ React7.createElement("div", {
745
- className: theadResizeRoot({
746
- isResizing
747
- }),
748
- onDoubleClick: header.column.resetSize,
749
- onMouseDown: onResize,
750
- onTouchStart: onResize
751
- }));
752
- }), tableContext.expand && /* @__PURE__ */ React7.createElement("th", null))
753
- );
754
- }));
755
- };
756
- TableHead.displayName = TABLE_HEAD_NAME;
757
-
758
- // packages/ui/react-ui-table/src/components/Table/Table.tsx
759
- var TableRoot = ({ children }) => {
760
- const contextValue = useTableRootContext();
761
- return /* @__PURE__ */ React8.createElement(TableRootContext.Provider, {
762
- value: contextValue
763
- }, children);
764
- };
765
- var TableViewport = ({ children, classNames, asChild, ...props }) => {
766
- const { scrollContextRef } = useContext3(TableRootContext);
767
- const classes = mx4(classNames, "overflow-auto");
768
- return asChild ? /* @__PURE__ */ React8.createElement(Slot, {
769
- ref: scrollContextRef,
770
- className: classes,
771
- ...props
772
- }, children) : /* @__PURE__ */ React8.createElement("div", {
773
- role: "none",
774
- className: classes,
775
- ref: scrollContextRef,
776
- ...props
777
- }, children);
778
- };
779
- var TablePrimitive = (props) => {
780
- const { role, header = true, rowsSelectable, debug, pinLastRow, columnVisibility, onColumnResize, onDataSelectionChange } = props;
781
- const columns = useDefaultValue(props.columns, () => []);
782
- const incomingData = useDefaultValue(props.data, () => []);
783
- const [data, setData] = useState8([
784
- ...incomingData
495
+ };
496
+ }, [
497
+ model,
498
+ dxGrid
785
499
  ]);
786
- const forceUpdate = useCallback7(() => setData([
787
- ...incomingData
788
- ]), [
789
- incomingData
500
+ const handleFocus = (increment, delta) => {
501
+ dxGrid?.refocus(increment, delta);
502
+ };
503
+ const handleEnter = useCallback3((cell) => {
504
+ if (model && cell.row === model.getRowCount() - 1) {
505
+ model.insertRow(cell.row);
506
+ }
507
+ }, [
508
+ model
790
509
  ]);
791
- useEffect3(() => forceUpdate(), [
792
- JSON.stringify(incomingData),
793
- forceUpdate
510
+ const handleKeyDown = useCallback3((event) => {
511
+ const cell = closestCell(event.target);
512
+ if (!model || !cell) {
513
+ return;
514
+ }
515
+ switch (event.key) {
516
+ case "Backspace":
517
+ case "Delete": {
518
+ model.setCellData(cell, void 0);
519
+ break;
520
+ }
521
+ }
522
+ }, [
523
+ model
794
524
  ]);
795
- const TableProvider2 = TableProvider;
796
- const { columnSizing, setColumnSizing, columnSizingInfo, setColumnSizingInfo } = useColumnResizing({
797
- columns,
798
- onColumnResize
799
- });
800
- const { rowSelection, handleRowSelectionChange } = useRowSelection(props);
801
- const [grouping, handleGroupingChange] = useState8(props.grouping ?? []);
802
- useEffect3(() => handleGroupingChange(props.grouping ?? []), [
803
- handleGroupingChange,
804
- props.grouping
525
+ const handleAxisResize = useCallback3((event) => {
526
+ if (event.axis === "col") {
527
+ const columnIndex = parseInt(event.index, 10);
528
+ model?.setColumnWidth(columnIndex, event.size);
529
+ }
530
+ }, [
531
+ model
805
532
  ]);
806
- const columnSorting = useColumnSorting();
807
- const table = useReactTable({
808
- // Data
809
- meta: {},
810
- data,
811
- // Columns
812
- columns,
813
- defaultColumn: {
814
- size: 400,
815
- maxSize: 1024
816
- },
817
- // State
818
- state: {
819
- columnVisibility,
820
- columnSizing,
821
- columnSizingInfo,
822
- sorting: columnSorting.sorting,
823
- rowSelection,
824
- grouping
825
- },
826
- // Resize columns
827
- columnResizeMode: "onChange",
828
- enableColumnResizing: true,
829
- onColumnSizingChange: setColumnSizing,
830
- onColumnSizingInfoChange: setColumnSizingInfo,
831
- // Rows
832
- getCoreRowModel: getCoreRowModel(),
833
- getSortedRowModel: getSortedRowModel(),
834
- getExpandedRowModel: getExpandedRowModel(),
835
- // Grouping
836
- getGroupedRowModel: grouping.length > 1 ? getGroupedRowModel() : void 0,
837
- onGroupingChange: handleGroupingChange,
838
- enableMultiRowSelection: rowsSelectable === "multi" ? true : void 0,
839
- enableRowSelection: rowsSelectable === true ? true : void 0,
840
- onRowSelectionChange: handleRowSelectionChange,
841
- enableSorting: true,
842
- enableColumnPinning: true,
843
- // Debug
844
- debugTable: debug
845
- });
846
- useEffect3(() => {
847
- onDataSelectionChange?.(Object.keys(rowSelection).map((id) => table.getRowModel().rowsById[id].original));
533
+ const handleWheel = useCallback3((event) => {
534
+ if (!hasAttention) {
535
+ event.stopPropagation();
536
+ }
848
537
  }, [
849
- onDataSelectionChange,
850
- rowSelection,
851
- table
538
+ hasAttention
852
539
  ]);
853
- usePinLastRow(pinLastRow, table, data);
854
- const expand = false;
855
- return /* @__PURE__ */ React8.createElement(TableProvider2, {
856
- ...props,
857
- ...columnSorting,
858
- table,
859
- header,
860
- expand,
861
- isGrid: role === "grid" || role === "treegrid"
862
- }, /* @__PURE__ */ React8.createElement(TableImpl, {
863
- debug: false,
864
- ...props
865
- }));
866
- };
867
- var TableImpl = (props) => {
868
- const { debug, classNames, role, grouping, fullWidth } = props;
869
- const { table } = useTableContext();
870
- if (debug) {
871
- return /* @__PURE__ */ React8.createElement("pre", {
872
- className: "font-mono text-xs text-neutral-500 m-1 p-2 ring"
873
- }, /* @__PURE__ */ React8.createElement("code", null, JSON.stringify(table.getState(), void 0, 2)));
874
- }
875
- const isResizingColumn = table.getState().columnSizingInfo.isResizingColumn;
876
- const TableComponent = isResizingColumn ? MemoizedVirtualizedTableContent : VirtualizedTableContent;
877
- return /* @__PURE__ */ React8.createElement("table", {
878
- role,
879
- className: tableRoot(props, classNames),
880
- style: {
881
- // borderCollapse: 'separate',
882
- borderSpacing: 0,
883
- ...!fullWidth && {
884
- width: table.getTotalSize()
540
+ const handleQuery = useCallback3(async ({ field, props }, _text) => {
541
+ if (model && props.referenceSchema && field.referencePath) {
542
+ const space = getSpace2(model.table);
543
+ invariant2(space, void 0, {
544
+ F: __dxlog_file3,
545
+ L: 150,
546
+ S: void 0,
547
+ A: [
548
+ "space",
549
+ ""
550
+ ]
551
+ });
552
+ const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
553
+ if (schema) {
554
+ const { objects } = await space.db.query(Filter.schema(schema)).run();
555
+ return objects.map((obj) => {
556
+ const value = getValue(obj, field.referencePath);
557
+ if (!value || typeof value !== "string") {
558
+ return void 0;
559
+ }
560
+ return {
561
+ label: value,
562
+ data: obj
563
+ };
564
+ }).filter(isNotFalsy);
885
565
  }
886
566
  }
887
- }, /* @__PURE__ */ React8.createElement(TableHead, null), grouping?.length !== 0 ? /* @__PURE__ */ React8.createElement(TableComponent, null) : /* @__PURE__ */ React8.createElement(GroupedTableContent, null));
888
- };
889
- var VirtualizedTableContent = () => {
890
- const { table } = useTableContext();
891
- const { virtualizer, dispatch } = useContext3(TableRootContext);
892
- const centerRows = table.getCenterRows();
893
- let pinnedRows = [];
894
- useEffect3(() => {
895
- dispatch({
896
- type: "updateTableCount",
897
- count: centerRows.length
898
- });
567
+ return [];
899
568
  }, [
900
- centerRows.length
569
+ model
901
570
  ]);
902
- try {
903
- pinnedRows = table.getBottomRows();
904
- } catch (_) {
571
+ if (!model) {
572
+ return /* @__PURE__ */ React5.createElement("span", {
573
+ role: "none",
574
+ className: "attention-surface"
575
+ });
905
576
  }
906
- const { getTotalSize, getVirtualItems } = virtualizer;
907
- const virtualRows = getVirtualItems();
908
- const totalSize = getTotalSize();
909
- const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
910
- const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) : 0;
911
- const rowsToRender = [
912
- ...virtualRows.map((virtualRow) => centerRows[virtualRow.index]),
913
- ...pinnedRows
914
- ].filter((r) => !!r);
915
- return /* @__PURE__ */ React8.createElement(Fragment, null, paddingTop > 0 && /* @__PURE__ */ React8.createElement("tbody", {
916
- role: "none"
917
- }, /* @__PURE__ */ React8.createElement("tr", {
918
- role: "none"
919
- }, /* @__PURE__ */ React8.createElement("td", {
920
- style: {
921
- height: `${paddingTop}px`
922
- },
923
- role: "none"
924
- }))), /* @__PURE__ */ React8.createElement(TableBody, {
925
- rows: rowsToRender
926
- }), paddingBottom > 0 && /* @__PURE__ */ React8.createElement("tbody", {
927
- role: "none"
928
- }, /* @__PURE__ */ React8.createElement("tr", {
929
- role: "none"
930
- }, /* @__PURE__ */ React8.createElement("td", {
931
- style: {
932
- height: `${paddingBottom}px`
933
- },
934
- role: "none"
935
- }))));
936
- };
937
- var MemoizedVirtualizedTableContent = /* @__PURE__ */ memo(VirtualizedTableContent);
938
- var GroupedTableContent = () => {
939
- const { table: { getGroupedRowModel: getGroupedRowModel2, getHeaderGroups, getState }, debug } = useTableContext();
940
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, getGroupedRowModel2().rows.map((row, i) => {
941
- return /* @__PURE__ */ React8.createElement(Fragment, {
942
- key: i
943
- }, /* @__PURE__ */ React8.createElement("thead", null, /* @__PURE__ */ React8.createElement("tr", null, debug && /* @__PURE__ */ React8.createElement("th", null), /* @__PURE__ */ React8.createElement("th", {
944
- // TODO(burdon): Calculate row span.
945
- colSpan: getHeaderGroups()[0].headers.length,
946
- className: groupTh({})
947
- }, getState().grouping[0], "[", String(row.getGroupingValue(getState().grouping[0])), "]"))), /* @__PURE__ */ React8.createElement(TableBody, {
948
- rows: row.subRows
949
- }));
577
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Grid.Root, {
578
+ id: model.table.id ?? "table-grid"
579
+ }, /* @__PURE__ */ React5.createElement(TableCellEditor, {
580
+ model,
581
+ onEnter: handleEnter,
582
+ onFocus: handleFocus,
583
+ onQuery: handleQuery
584
+ }), /* @__PURE__ */ React5.createElement(Grid.Content, {
585
+ onWheelCapture: handleWheel,
586
+ className: mx("[--dx-grid-base:var(--surface-bg)] [&_.dx-grid]:bs-min [&_.dx-grid]:shrink [&_.dx-grid]:max-is-max", inlineEndLine, blockEndLine),
587
+ frozen,
588
+ columns: model.columnMeta.value,
589
+ limitRows: model.getRowCount() ?? 0,
590
+ limitColumns: model.table.view?.fields?.length ?? 0,
591
+ onAxisResize: handleAxisResize,
592
+ onClick: model?.handleGridClick,
593
+ onKeyDown: handleKeyDown,
594
+ overscroll: "trap",
595
+ ref: setDxGrid
596
+ })), /* @__PURE__ */ React5.createElement(RowActionsMenu, {
597
+ model
598
+ }), /* @__PURE__ */ React5.createElement(ColumnActionsMenu, {
599
+ model
600
+ }), /* @__PURE__ */ React5.createElement(ColumnSettings, {
601
+ model
950
602
  }));
951
- };
603
+ });
952
604
  var Table = {
953
605
  Root: TableRoot,
954
- Viewport: TableViewport,
955
- Main: TablePrimitive
606
+ Main: TableMain
956
607
  };
957
608
 
958
- // packages/ui/react-ui-table/src/helpers.tsx
959
- import { useFocusFinders } from "@fluentui/react-tabster";
960
- import { Check, ClipboardText, X as X2 } from "@phosphor-icons/react";
961
- import { createColumnHelper } from "@tanstack/react-table";
962
- import { format } from "date-fns/format";
963
- import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
964
- import React9, { useCallback as useCallback8, useEffect as useEffect4, useRef as useRef4, useState as useState9 } from "react";
965
- import { log } from "@dxos/log";
966
- import { Input as Input2, Tooltip } from "@dxos/react-ui";
967
- import { getSize as getSize3, mx as mx5 } from "@dxos/react-ui-theme";
968
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/helpers.tsx";
969
- var createColumnBuilder = () => ({
970
- helper: createColumnHelper(),
971
- builder: new ColumnBuilder()
609
+ // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
610
+ import { ChatText, RowsPlusBottom } from "@phosphor-icons/react";
611
+ import { createContext } from "@radix-ui/react-context";
612
+ import React7 from "react";
613
+ import { Toolbar as NaturalToolbar2, useTranslation as useTranslation3 } from "@dxos/react-ui";
614
+
615
+ // packages/ui/react-ui-table/src/components/Toolbar/common.tsx
616
+ import React6 from "react";
617
+ import { Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
618
+ import { getSize } from "@dxos/react-ui-theme";
619
+ var iconStyles = getSize(5);
620
+ var buttonStyles = "min-bs-0 p-2";
621
+ var tooltipProps = {
622
+ side: "top",
623
+ classNames: "z-10"
624
+ };
625
+ var ToolbarSeparator = () => /* @__PURE__ */ React6.createElement("div", {
626
+ role: "separator",
627
+ className: "grow"
972
628
  });
973
- var ComboboxBuilderCell = (cellContext) => {
974
- const { model, onUpdate } = cellContext.column.columnDef.meta;
975
- return model ? /* @__PURE__ */ React9.createElement(CellCombobox, {
976
- model,
977
- value: cellContext.getValue(),
978
- onValueChange: (value) => onUpdate?.(cellContext.row.original, cellContext.column.id, value)
979
- }) : null;
629
+ var ToolbarButton = ({ Icon, children, ...props }) => {
630
+ return /* @__PURE__ */ React6.createElement(Tooltip.Root, null, /* @__PURE__ */ React6.createElement(Tooltip.Trigger, {
631
+ asChild: true
632
+ }, /* @__PURE__ */ React6.createElement(NaturalToolbar.Button, {
633
+ variant: "ghost",
634
+ ...props,
635
+ classNames: buttonStyles
636
+ }, /* @__PURE__ */ React6.createElement(Icon, {
637
+ className: iconStyles
638
+ }), /* @__PURE__ */ React6.createElement("span", {
639
+ className: "sr-only"
640
+ }, children))), /* @__PURE__ */ React6.createElement(Tooltip.Portal, null, /* @__PURE__ */ React6.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React6.createElement(Tooltip.Arrow, null))));
980
641
  };
981
- var StringBuilderCell = (cellContext) => {
982
- const ref = useRef4(null);
983
- const { findPrevFocusable } = useFocusFinders();
984
- const { onUpdate, cell } = cellContext.column.columnDef.meta;
985
- const initialValue = cellContext.getValue();
986
- const getInitialValue = useCallback8(() => {
987
- return initialValue?.content ?? initialValue;
988
- }, [
989
- initialValue
990
- ]);
991
- const [value, setValue] = useState9(getInitialValue);
992
- useEffect4(() => setValue(getInitialValue()), [
993
- getInitialValue
994
- ]);
995
- const handleSave = () => {
996
- ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
997
- if (value !== initialValue) {
998
- onUpdate?.(cellContext.row.original, cellContext.column.id, value);
999
- }
1000
- };
1001
- const handleCancel = () => setValue(initialValue);
1002
- let placeholder = false;
1003
- const columns = cellContext.table.getVisibleFlatColumns();
1004
- if (columns[0].id === cellContext.column.id) {
1005
- const rowCount = cellContext.table.getRowModel().rows.length;
1006
- placeholder = cellContext.row.index === rowCount - 1 && columns[0].id === cellContext.column.id;
1007
- }
1008
- return /* @__PURE__ */ React9.createElement(Input2.Root, null, /* @__PURE__ */ React9.createElement(Input2.TextInput, {
1009
- ref,
1010
- variant: "subdued",
1011
- placeholder: placeholder ? "Add row..." : void 0,
642
+
643
+ // packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
644
+ var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
645
+ var ToolbarRoot = ({ classNames, children, onAction }) => {
646
+ return /* @__PURE__ */ React7.createElement(ToolbarContextProvider, {
647
+ onAction
648
+ }, /* @__PURE__ */ React7.createElement(NaturalToolbar2.Root, {
1012
649
  classNames: [
1013
- "is-full",
1014
- textPadding,
1015
- cell?.classNames
1016
- ],
1017
- value: value ?? "",
1018
- onBlur: handleSave,
1019
- onChange: (event) => setValue(event.target.value),
1020
- onKeyDown: (event) => event.key === "Enter" && handleSave() || event.key === "Escape" && handleCancel(),
1021
- autoComplete: "off"
1022
- }));
650
+ "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1",
651
+ classNames
652
+ ]
653
+ }, children));
1023
654
  };
1024
- var parseNumber = (text) => text?.trim().length ? Number(text) : NaN;
1025
- var displayNumber = (value, digits) => value || value === 0 ? value.toLocaleString(void 0, {
1026
- minimumFractionDigits: digits ?? 0,
1027
- maximumFractionDigits: digits ?? 2
1028
- }) : "";
1029
- var NumberBuilderCell = (cellContext) => {
1030
- const { onUpdate, digits } = cellContext.column.columnDef.meta;
1031
- const value = cellContext.getValue();
1032
- const [text, setText] = useState9(displayNumber(value, digits));
1033
- const { findPrevFocusable } = useFocusFinders();
1034
- const ref = useRef4(null);
1035
- useEffect4(() => {
1036
- (!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
1037
- }, [
1038
- digits,
1039
- value
1040
- ]);
1041
- const handleEdit = () => setText(value !== void 0 ? String(value) : "");
1042
- const handleSave = () => {
1043
- const nextValue = parseNumber(text);
1044
- if (!isNaN(nextValue)) {
1045
- onUpdate?.(cellContext.row.original, cellContext.column.id, nextValue);
1046
- setText(displayNumber(nextValue, digits));
1047
- } else {
1048
- setText(displayNumber(value, digits));
1049
- }
1050
- ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
1051
- };
1052
- const _handleCancel = () => {
1053
- setText(displayNumber(value, digits));
1054
- ref.current && findPrevFocusable(ref.current)?.focus();
1055
- };
1056
- return /* @__PURE__ */ React9.createElement(Input2.Root, null, /* @__PURE__ */ React9.createElement(Input2.TextInput, {
1057
- ref,
1058
- variant: "subdued",
1059
- value: text,
1060
- classNames: [
1061
- "is-full text-end font-mono",
1062
- textPadding
1063
- ],
1064
- onBlur: handleSave,
1065
- onFocus: handleEdit,
1066
- onChange: ({ target: { value: value2 } }) => setText(value2),
1067
- onKeyDown: (event) => {
1068
- return (
1069
- /* (event.key === 'Escape' && handleCancel()) || */
1070
- event.key === "Enter" && handleSave()
1071
- );
1072
- },
1073
- autoComplete: "off"
1074
- }));
655
+ var Editing = () => {
656
+ const { onAction } = useToolbarContext("Editing");
657
+ const { t } = useTranslation3(translationKey);
658
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(ToolbarButton, {
659
+ value: "add-row",
660
+ Icon: RowsPlusBottom,
661
+ "data-testid": "table.toolbar.add-row",
662
+ onClick: () => onAction?.({
663
+ type: "add-row"
664
+ })
665
+ }, t("add row")));
1075
666
  };
1076
- var RowSelectorBuilderCell = (cellContext) => {
1077
- const { cell } = cellContext.column.columnDef.meta;
1078
- const { row } = cellContext;
1079
- const checked = row.getCanSelect() ? row.getIsSelected() : row.getCanSelectSubRows() && (row.getIsSomeSelected() ? "indeterminate" : row.getIsAllSubRowsSelected());
1080
- return /* @__PURE__ */ React9.createElement("div", {
1081
- className: "flex justify-center w-full h-full",
1082
- role: "presentation"
1083
- }, /* @__PURE__ */ React9.createElement(Input2.Root, null, /* @__PURE__ */ React9.createElement(Input2.Checkbox, {
1084
- size: 4,
1085
- classNames: [
1086
- cell?.classNames
1087
- ],
1088
- checked,
1089
- onCheckedChange: (event) => {
1090
- if (row.getCanSelect()) {
1091
- row.getToggleSelectedHandler()(event);
1092
- }
1093
- },
1094
- disabled: !(row.getCanSelect() || row.getCanSelectSubRows())
1095
- })));
667
+ var Actions = () => {
668
+ const { onAction } = useToolbarContext("Actions");
669
+ const { t } = useTranslation3(translationKey);
670
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(ToolbarButton, {
671
+ value: "comment",
672
+ Icon: ChatText,
673
+ "data-testid": "table.toolbar.comment",
674
+ onClick: () => onAction?.({
675
+ type: "comment"
676
+ })
677
+ }, t("create comment")));
1096
678
  };
1097
- var SwitchBuilderCell = (cellContext) => {
1098
- const { onUpdate } = cellContext.column.columnDef.meta;
1099
- const value = cellContext.getValue();
1100
- return /* @__PURE__ */ React9.createElement(Input2.Root, null, /* @__PURE__ */ React9.createElement(Input2.Switch, {
1101
- classNames: "block mli-auto",
1102
- onClick: (event) => event.stopPropagation(),
1103
- disabled: !onUpdate,
1104
- checked: !!value,
1105
- onCheckedChange: (value2) => {
1106
- onUpdate?.(cellContext.row.original, cellContext.column.id, !!value2);
1107
- }
1108
- }));
679
+ var Toolbar = {
680
+ Root: ToolbarRoot,
681
+ Editing,
682
+ Actions,
683
+ Separator: ToolbarSeparator
1109
684
  };
1110
- var ColumnBuilder = class {
1111
- /**
1112
- * Combobox value
1113
- */
1114
- combobox({ label, classNames, model, onUpdate, ...props }) {
1115
- return {
1116
- minSize: 100,
1117
- header: (column) => {
1118
- return label ?? column.header.id;
1119
- },
1120
- cell: model && onUpdate ? ComboboxBuilderCell : (cellContext) => {
1121
- const cellValue = cellContext.getValue();
1122
- return /* @__PURE__ */ React9.createElement("div", {
1123
- className: mx5("truncate", classNames)
1124
- }, cellValue ? model?.getText(cellValue) : "");
1125
- },
1126
- ...props,
1127
- meta: {
1128
- ...props.meta,
1129
- model,
1130
- onUpdate,
1131
- cell: {
1132
- classNames,
1133
- ...props.meta?.cell
1134
- }
685
+
686
+ // packages/ui/react-ui-table/src/hooks/useTableModel.ts
687
+ import { useEffect as useEffect2, useState as useState3 } from "react";
688
+
689
+ // packages/ui/react-ui-table/src/model/table-model.ts
690
+ import { computed as computed2, effect as effect2, signal as signal3 } from "@preact/signals-core";
691
+ import orderBy from "lodash.orderby";
692
+ import { Resource as Resource2 } from "@dxos/context";
693
+ import { getValue as getValue2, setValue, FormatEnum as FormatEnum3 } from "@dxos/echo-schema";
694
+ import { invariant as invariant3 } from "@dxos/invariant";
695
+ import { PublicKey as PublicKey2 } from "@dxos/react-client";
696
+ import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay, formatForEditing, parseValue } from "@dxos/react-ui-data";
697
+ import { mx as mx2 } from "@dxos/react-ui-theme";
698
+ import { VIEW_FIELD_LIMIT } from "@dxos/schema";
699
+
700
+ // packages/ui/react-ui-table/src/model/modal-controller.ts
701
+ import { signal } from "@preact/signals-core";
702
+ var ModalController = class {
703
+ constructor() {
704
+ this._state = signal({
705
+ type: "closed"
706
+ });
707
+ this._triggerRef = {
708
+ current: null
709
+ };
710
+ this.handleClick = (event) => {
711
+ const target = event.target;
712
+ const rowButton = target.closest(`button[${tableButtons.rowMenu.attr}]`);
713
+ if (rowButton) {
714
+ this._triggerRef.current = rowButton;
715
+ this._state.value = {
716
+ type: "row",
717
+ rowIndex: Number(rowButton.getAttribute(tableButtons.rowMenu.attr))
718
+ };
719
+ return true;
720
+ }
721
+ const columnButton = target.closest(`button[${tableButtons.columnSettings.attr}]`);
722
+ if (columnButton) {
723
+ const fieldId = columnButton.getAttribute(tableButtons.columnSettings.attr);
724
+ this._triggerRef.current = columnButton;
725
+ this._state.value = {
726
+ type: "column",
727
+ fieldId
728
+ };
729
+ return true;
1135
730
  }
731
+ const addColumnButton = target.closest(`button[${tableButtons.addColumn.attr}]`);
732
+ if (addColumnButton) {
733
+ this._triggerRef.current = addColumnButton;
734
+ this._state.value = {
735
+ type: "columnSettings",
736
+ mode: {
737
+ type: "create"
738
+ }
739
+ };
740
+ return true;
741
+ }
742
+ return false;
1136
743
  };
1137
- }
1138
- /**
1139
- * String formats.
1140
- */
1141
- string({ label, classNames, onUpdate, ...props } = {}) {
1142
- return {
1143
- minSize: 100,
1144
- // TODO(burdon): Default.
1145
- header: (column) => {
1146
- return label ?? column.header.id;
1147
- },
1148
- cell: onUpdate ? StringBuilderCell : (cell) => {
1149
- let value = cell.getValue();
1150
- if (typeof value === "object" && value?.__typename === "dxos.Text.v0") {
1151
- value = value.content;
1152
- }
1153
- return /* @__PURE__ */ React9.createElement("div", {
1154
- className: mx5("truncate", textPadding, classNames)
1155
- }, value);
1156
- },
1157
- ...props,
1158
- meta: {
1159
- ...props.meta,
1160
- onUpdate,
1161
- cell: {
1162
- ...props.meta?.cell,
1163
- classNames
1164
- }
744
+ this.openColumnSettings = () => {
745
+ if (this._state.value.type === "column") {
746
+ const fieldId = this._state.value.fieldId;
747
+ requestAnimationFrame(() => {
748
+ this._state.value = {
749
+ type: "columnSettings",
750
+ mode: {
751
+ type: "edit",
752
+ fieldId
753
+ }
754
+ };
755
+ });
1165
756
  }
1166
757
  };
758
+ this.close = () => {
759
+ this._state.value = {
760
+ type: "closed"
761
+ };
762
+ };
1167
763
  }
1168
- /**
1169
- * Number formats.
1170
- */
1171
- number({ label, minSize, classNames, digits, onUpdate, ...props } = {}) {
1172
- return {
1173
- size: 100,
1174
- minSize: 100,
1175
- header: (cell) => label ?? cell.header.id,
1176
- cell: NumberBuilderCell,
1177
- ...props,
1178
- meta: {
1179
- ...props.meta,
1180
- onUpdate,
1181
- digits,
1182
- header: {
1183
- ...props.meta?.header
1184
- },
1185
- cell: {
1186
- ...props.meta?.cell,
1187
- classNames
1188
- }
764
+ get state() {
765
+ return this._state;
766
+ }
767
+ get trigger() {
768
+ return this._triggerRef;
769
+ }
770
+ };
771
+
772
+ // packages/ui/react-ui-table/src/model/selection-model.ts
773
+ import { computed, effect, signal as signal2 } from "@preact/signals-core";
774
+ import { Resource } from "@dxos/context";
775
+ var SelectionModel = class extends Resource {
776
+ constructor(_rows, _onSelectionChanged) {
777
+ super();
778
+ this._rows = _rows;
779
+ this._onSelectionChanged = _onSelectionChanged;
780
+ this._selection = signal2(/* @__PURE__ */ new Set());
781
+ this._validSelectedIds = computed(() => {
782
+ const rows = this._rows.value;
783
+ if (!rows) {
784
+ return /* @__PURE__ */ new Set();
785
+ }
786
+ const validIds = new Set(rows.map((row) => row.id));
787
+ return new Set([
788
+ ...this._selection.value
789
+ ].filter((id) => validIds.has(id)));
790
+ });
791
+ this._hasSelection = computed(() => this._validSelectedIds.value.size > 0);
792
+ this._allSelected = computed(() => {
793
+ const rows = this._rows.value;
794
+ if (rows.length === 0) {
795
+ return false;
796
+ }
797
+ return rows.length !== 0 || rows.every((row) => this._selection.value.has(row.id));
798
+ });
799
+ this.getSelectedRows = () => {
800
+ const selectedIds = this._validSelectedIds.value;
801
+ return this._rows.value.filter((row) => selectedIds.has(row.id));
802
+ };
803
+ this.isRowIndexSelected = (rowIndex) => {
804
+ const row = this._rows.value[rowIndex];
805
+ return this._selection.value.has(row.id);
806
+ };
807
+ this.isObjectSelected = (object) => {
808
+ return this._selection.value.has(object.id);
809
+ };
810
+ this.toggleSelectionForRowIndex = (rowIndex) => {
811
+ const row = this._rows.value[rowIndex];
812
+ const newSelection = new Set(this._selection.value);
813
+ if (newSelection.has(row.id)) {
814
+ newSelection.delete(row.id);
815
+ } else {
816
+ newSelection.add(row.id);
1189
817
  }
818
+ this._selection.value = newSelection;
819
+ };
820
+ this.setSelection = (mode) => {
821
+ this._selection.value = mode === "all" ? new Set(this._rows.value.map((row) => row.id)) : /* @__PURE__ */ new Set();
1190
822
  };
1191
823
  }
1192
- /**
1193
- * Date formats.
1194
- */
1195
- // TODO(burdon): Date picker (pluggable renderers?)
1196
- date({ label, format: formatSpec, relative, classNames, ...props } = {}) {
1197
- return {
1198
- size: 220,
1199
- minSize: 100,
1200
- header: (cell) => label ?? cell.header.id,
1201
- cell: (cell) => {
1202
- const value = cell.getValue();
1203
- try {
1204
- const str = value ? formatSpec ? format(value, formatSpec) : relative ? formatDistanceToNow(value, {
1205
- addSuffix: true
1206
- }) : value.toISOString() : void 0;
1207
- return /* @__PURE__ */ React9.createElement("div", {
1208
- className: mx5(textPadding, classNames)
1209
- }, str);
1210
- } catch (err) {
1211
- log.info("formatError", {
1212
- value
1213
- }, {
1214
- F: __dxlog_file,
1215
- L: 377,
1216
- S: this,
1217
- C: (f, a) => f(...a)
1218
- });
1219
- return null;
1220
- }
824
+ async _open() {
825
+ const selectionWatcher = effect(() => {
826
+ touch(this._selection.value);
827
+ this._onSelectionChanged?.();
828
+ });
829
+ this._ctx.onDispose(selectionWatcher);
830
+ }
831
+ //
832
+ // Getters
833
+ //
834
+ get selection() {
835
+ return this._selection;
836
+ }
837
+ get hasSelection() {
838
+ return this._hasSelection;
839
+ }
840
+ get allRowsSeleted() {
841
+ return this._allSelected;
842
+ }
843
+ };
844
+
845
+ // packages/ui/react-ui-table/src/util/table-controls.ts
846
+ var checkboxAttributes = {
847
+ checkbox: "data-table-checkbox",
848
+ header: "data-table-header"
849
+ };
850
+ var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = false }) => {
851
+ const baseClasses = "absolute inset-block-[6px] inline-end-[6px]";
852
+ const { attributes } = tableControls.checkbox;
853
+ return `<input type="checkbox" class="${baseClasses}" ${attributes.checkbox}="${rowIndex}" ${header ? attributes.header : ""} ${checked ? "checked" : ""} ${disabled ? "disabled" : ""}/>`;
854
+ };
855
+ var tableControls = {
856
+ checkbox: {
857
+ attributes: checkboxAttributes,
858
+ render: renderCheckbox
859
+ }
860
+ };
861
+
862
+ // packages/ui/react-ui-table/src/model/table-model.ts
863
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
864
+ var TableModel = class extends Resource2 {
865
+ constructor({ table, projection, sorting = [], pinnedRows = {
866
+ top: [],
867
+ bottom: []
868
+ }, onCellUpdate, onDeleteColumn, onDeleteRows, onInsertRow, onRowOrderChanged }) {
869
+ super();
870
+ this.id = `table-model-${PublicKey2.random().truncate()}`;
871
+ this._visibleRange = signal3({
872
+ start: {
873
+ row: 0,
874
+ col: 0
1221
875
  },
1222
- ...props,
1223
- meta: {
1224
- ...props.meta,
1225
- cell: {
1226
- ...props.meta?.cell,
1227
- classNames
876
+ end: {
877
+ row: 0,
878
+ col: 0
879
+ }
880
+ });
881
+ /**
882
+ * Maps display indices to data indices.
883
+ * Used for translating between sorted/displayed order and original data order.
884
+ * Keys are display indices, values are corresponding data indices.
885
+ */
886
+ this._displayToDataIndex = /* @__PURE__ */ new Map();
887
+ this._sorting = signal3(void 0);
888
+ this._rows = signal3([]);
889
+ this._modalController = new ModalController();
890
+ //
891
+ // Get Cells
892
+ //
893
+ this.getCells = (range, plane) => {
894
+ switch (plane) {
895
+ case "grid": {
896
+ this._visibleRange.value = range;
897
+ return this.getMainGridCells(range);
898
+ }
899
+ case "frozenRowsStart": {
900
+ return this.getHeaderCells(range);
901
+ }
902
+ case "frozenColsStart": {
903
+ return this.getSelectionColumnCells(range);
904
+ }
905
+ case "frozenColsEnd": {
906
+ return this.getActionColumnCells(range);
907
+ }
908
+ case "fixedStartStart": {
909
+ return this.getSelectAllCell();
910
+ }
911
+ case "fixedStartEnd": {
912
+ return this.getNewColumnCell();
913
+ }
914
+ default: {
915
+ return {};
1228
916
  }
1229
917
  }
1230
918
  };
1231
- }
1232
- /**
1233
- * PublicKey with tooltip.
1234
- */
1235
- key({ label, tooltip, classNames, ...props } = {}) {
1236
- return {
1237
- size: 94,
1238
- minSize: 94,
1239
- header: (cell) => label ?? cell.header.id,
1240
- cell: (cell) => {
1241
- const value = cell.getValue();
1242
- if (!value) {
1243
- return;
919
+ this.getMainGridCells = (range) => {
920
+ const values = {};
921
+ const fields = this._table.view?.fields ?? [];
922
+ const addCell = (obj, field, colIndex, displayIndex) => {
923
+ const { props } = this._projection.getFieldProjection(field.id);
924
+ const value = {
925
+ get value() {
926
+ const value2 = getValue2(obj, field.path);
927
+ if (value2 == null) {
928
+ return "";
929
+ }
930
+ switch (props.format) {
931
+ case FormatEnum3.Ref: {
932
+ if (!field.referencePath) {
933
+ return "";
934
+ }
935
+ return getValue2(value2, field.referencePath);
936
+ }
937
+ default: {
938
+ return formatForDisplay({
939
+ type: props.type,
940
+ format: props.format,
941
+ value: value2
942
+ });
943
+ }
944
+ }
945
+ }
946
+ };
947
+ const classes = [];
948
+ const formatClasses = cellClassesForFieldType({
949
+ type: props.type,
950
+ format: props.format
951
+ });
952
+ if (formatClasses) {
953
+ classes.push(formatClasses);
954
+ }
955
+ const rowSelectionClasses = cellClassesForRowSelection(this._selection.isObjectSelected(obj));
956
+ if (rowSelectionClasses) {
957
+ classes.push(rowSelectionClasses);
1244
958
  }
1245
- const element = value.truncate();
1246
- if (!tooltip) {
1247
- return element;
959
+ if (classes.length > 0) {
960
+ value.className = mx2(classes.flat());
1248
961
  }
1249
- return /* @__PURE__ */ React9.createElement(Tooltip.Provider, null, /* @__PURE__ */ React9.createElement(Tooltip.Root, null, /* @__PURE__ */ React9.createElement(Tooltip.Trigger, null, element), /* @__PURE__ */ React9.createElement(Tooltip.Portal, null, /* @__PURE__ */ React9.createElement(Tooltip.Content, {
1250
- side: "right"
1251
- }, /* @__PURE__ */ React9.createElement(Tooltip.Arrow, null), /* @__PURE__ */ React9.createElement(ClipboardText, {
1252
- onClick: (ev) => {
1253
- ev.stopPropagation();
1254
- void navigator.clipboard.writeText(value.toHex());
962
+ const idx = fromGridCell({
963
+ col: colIndex,
964
+ row: displayIndex
965
+ });
966
+ values[idx] = value;
967
+ };
968
+ for (let row = range.start.row; row <= range.end.row && row < this._sortedRows.value.length; row++) {
969
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
970
+ const field = fields[col];
971
+ if (!field) {
972
+ continue;
1255
973
  }
1256
- })))));
1257
- },
1258
- ...props,
1259
- meta: {
1260
- ...props.meta,
1261
- cell: {
1262
- ...props.meta?.cell,
1263
- classNames: [
1264
- "font-mono",
1265
- textPadding,
1266
- classNames
1267
- ]
974
+ addCell(this._sortedRows.value[row], field, col, row);
1268
975
  }
1269
976
  }
977
+ return values;
1270
978
  };
1271
- }
1272
- /**
1273
- * Row selector
1274
- */
1275
- selectRow({ classNames, onUpdate, id = "selectRow" } = {}) {
1276
- return {
1277
- id,
1278
- size: 32,
1279
- enableResizing: false,
1280
- meta: {
1281
- onUpdate,
1282
- cell: {
1283
- classNames
979
+ this.getHeaderCells = (range) => {
980
+ const values = {};
981
+ const fields = this.table.view?.fields ?? [];
982
+ for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
983
+ const { field, props } = this._projection.getFieldProjection(fields[col].id);
984
+ values[fromGridCell({
985
+ col,
986
+ row: 0
987
+ })] = {
988
+ value: props.title ?? field.path,
989
+ readonly: true,
990
+ resizeHandle: "col",
991
+ accessoryHtml: tableButtons.columnSettings.render({
992
+ fieldId: field.id
993
+ })
994
+ };
995
+ }
996
+ return values;
997
+ };
998
+ this.getSelectionColumnCells = (range) => {
999
+ const values = {};
1000
+ for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1001
+ const isSelected = this._selection.isRowIndexSelected(row);
1002
+ const classes = cellClassesForRowSelection(isSelected);
1003
+ values[fromGridCell({
1004
+ col: 0,
1005
+ row
1006
+ })] = {
1007
+ value: "",
1008
+ readonly: true,
1009
+ className: classes ? mx2(classes) : void 0,
1010
+ accessoryHtml: tableControls.checkbox.render({
1011
+ rowIndex: row,
1012
+ checked: isSelected
1013
+ })
1014
+ };
1015
+ }
1016
+ return values;
1017
+ };
1018
+ this.getActionColumnCells = (range) => {
1019
+ const values = {};
1020
+ for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
1021
+ const isSelected = this._selection.isRowIndexSelected(row);
1022
+ const classes = cellClassesForRowSelection(isSelected);
1023
+ values[fromGridCell({
1024
+ col: 0,
1025
+ row
1026
+ })] = {
1027
+ value: "",
1028
+ readonly: true,
1029
+ className: classes ? mx2(classes) : void 0,
1030
+ accessoryHtml: tableButtons.rowMenu.render({
1031
+ rowIndex: row
1032
+ })
1033
+ };
1034
+ }
1035
+ return values;
1036
+ };
1037
+ this.getSelectAllCell = () => {
1038
+ return {
1039
+ [fromGridCell({
1040
+ col: 0,
1041
+ row: 0
1042
+ })]: {
1043
+ value: "",
1044
+ accessoryHtml: tableControls.checkbox.render({
1045
+ rowIndex: 0,
1046
+ header: true,
1047
+ checked: this._selection.allRowsSeleted.value
1048
+ }),
1049
+ readonly: true
1284
1050
  }
1285
- },
1286
- header: ({ table }) => {
1287
- const { rowsSelectable } = useTableContext();
1288
- const checked = table.getIsSomeRowsSelected() ? "indeterminate" : table.getIsAllRowsSelected();
1289
- return rowsSelectable === "multi" ? /* @__PURE__ */ React9.createElement("div", {
1290
- className: "flex justify-center w-full h-full",
1291
- role: "presentation"
1292
- }, /* @__PURE__ */ React9.createElement(Input2.Root, null, /* @__PURE__ */ React9.createElement(Input2.Checkbox, {
1293
- size: 4,
1294
- classNames: [
1295
- "mli-auto",
1296
- classNames
1297
- ],
1298
- checked,
1299
- onCheckedChange: () => table.toggleAllRowsSelected()
1300
- }))) : null;
1301
- },
1302
- cell: RowSelectorBuilderCell
1051
+ };
1303
1052
  };
1304
- }
1305
- /**
1306
- * Switch
1307
- */
1308
- switch({ label, classNames, onUpdate, ...props } = {}) {
1309
- return {
1310
- size: 50,
1311
- minSize: 50,
1312
- header: (column) => label ?? column.header.id,
1313
- // TODO(zan): Implement sort algorithm.
1314
- enableSorting: true,
1315
- cell: SwitchBuilderCell,
1316
- ...props,
1317
- meta: {
1318
- ...props.meta,
1319
- onUpdate,
1320
- cell: {
1321
- ...props.meta?.cell,
1322
- classNames: [
1323
- textPadding,
1324
- classNames
1325
- ]
1053
+ this.getNewColumnCell = () => {
1054
+ return {
1055
+ [fromGridCell({
1056
+ col: 0,
1057
+ row: 0
1058
+ })]: {
1059
+ value: "",
1060
+ accessoryHtml: tableButtons.addColumn.render({
1061
+ disabled: (this._table.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
1062
+ }),
1063
+ readonly: true
1326
1064
  }
1065
+ };
1066
+ };
1067
+ //
1068
+ // Data
1069
+ //
1070
+ this.setRows = (obj) => {
1071
+ this._rows.value = obj;
1072
+ };
1073
+ this.getRowCount = () => this._rows.value.length;
1074
+ this.getColumnCount = () => this.table.view?.fields.length ?? 0;
1075
+ this.insertRow = (rowIndex) => {
1076
+ const row = rowIndex !== void 0 ? this._displayToDataIndex.get(rowIndex) ?? rowIndex : this._rows.value.length;
1077
+ this._onInsertRow?.(row);
1078
+ };
1079
+ this.deleteRow = (rowIndex) => {
1080
+ const row = this._displayToDataIndex.get(rowIndex) ?? rowIndex;
1081
+ const obj = this._rows.value[row];
1082
+ const objectsToDelete = [];
1083
+ if (this._selection.hasSelection.value) {
1084
+ const selectedRows = this._selection.getSelectedRows();
1085
+ objectsToDelete.push(...selectedRows);
1086
+ } else {
1087
+ objectsToDelete.push(obj);
1327
1088
  }
1089
+ this._onDeleteRows?.(row, objectsToDelete);
1328
1090
  };
1329
- }
1330
- /**
1331
- * Icon based on boolean value.
1332
- */
1333
- icon({ label, size, on, off, ...props } = {}) {
1334
- const IconOn = on?.Icon ?? Check;
1335
- const IconOff = off?.Icon ?? X2;
1336
- return {
1337
- size: size ?? 32,
1338
- // TODO(zan): Implement sort algorithm.
1339
- enableSorting: false,
1340
- header: (column) => /* @__PURE__ */ React9.createElement("div", {
1341
- className: "justify-center"
1342
- }, label ?? column.header.id),
1343
- cell: (cell) => {
1344
- const value = cell.getValue();
1345
- if (value) {
1346
- return /* @__PURE__ */ React9.createElement(IconOn, {
1347
- className: mx5("block mli-auto", getSize3(6), on?.className ?? "text-green-700")
1348
- });
1349
- } else if (value === false) {
1350
- return /* @__PURE__ */ React9.createElement(IconOff, {
1351
- className: mx5("block mli-auto", getSize3(6), off?.className ?? "text-red-700")
1091
+ this.getCellData = ({ col, row }) => {
1092
+ const fields = this.table.view?.fields ?? [];
1093
+ if (col < 0 || col >= fields.length) {
1094
+ return void 0;
1095
+ }
1096
+ const field = fields[col];
1097
+ const dataIndex = this._displayToDataIndex.get(row) ?? row;
1098
+ const value = getValue2(this._rows.value[dataIndex], field.path);
1099
+ if (value == null) {
1100
+ return "";
1101
+ }
1102
+ const { props } = this._projection.getFieldProjection(field.id);
1103
+ switch (props.format) {
1104
+ case FormatEnum3.Ref: {
1105
+ if (!field.referencePath) {
1106
+ return "";
1107
+ }
1108
+ return getValue2(value, field.referencePath);
1109
+ }
1110
+ default: {
1111
+ return formatForEditing({
1112
+ type: props.type,
1113
+ format: props.format,
1114
+ value
1352
1115
  });
1353
- } else {
1354
- return null;
1355
1116
  }
1356
- },
1357
- ...props
1117
+ }
1358
1118
  };
1359
- }
1360
- /**
1361
- * This display column type is for nested/unhandled data to appear as JSON.
1362
- */
1363
- json({ label, classNames, ...props } = {}) {
1364
- return {
1365
- size: 120,
1366
- minSize: 120,
1367
- header: (cell) => label ?? cell.header.id,
1368
- cell: (cell) => {
1369
- const value = cell.getValue();
1370
- return /* @__PURE__ */ React9.createElement("div", {
1371
- className: "overflow-scroll"
1372
- }, /* @__PURE__ */ React9.createElement("code", {
1373
- className: "text-xs"
1374
- }, JSON.stringify(value)));
1375
- },
1376
- ...props,
1377
- meta: {
1378
- ...props.meta,
1379
- cell: {
1380
- ...props.meta?.cell,
1381
- classNames: [
1382
- "font-mono",
1383
- textPadding,
1384
- classNames
1385
- ]
1119
+ this.setCellData = ({ col, row }, value) => {
1120
+ const rowIdx = this._displayToDataIndex.get(row) ?? row;
1121
+ const fields = this.table.view?.fields ?? [];
1122
+ if (col < 0 || col >= fields.length) {
1123
+ return;
1124
+ }
1125
+ const field = fields[col];
1126
+ const { props } = this._projection.getFieldProjection(field.id);
1127
+ switch (props.format) {
1128
+ case FormatEnum3.Ref: {
1129
+ setValue(this._rows.value[rowIdx], field.path, value);
1130
+ break;
1131
+ }
1132
+ default: {
1133
+ setValue(this._rows.value[rowIdx], field.path, parseValue({
1134
+ type: props.type,
1135
+ format: props.format,
1136
+ value
1137
+ }));
1138
+ break;
1139
+ }
1140
+ }
1141
+ };
1142
+ //
1143
+ // Interactions
1144
+ //
1145
+ this.handleGridClick = (event) => {
1146
+ if (!this._modalController.handleClick(event)) {
1147
+ const target = event.target;
1148
+ const selectionCheckbox = target.closest(`input[${tableControls.checkbox.attributes.checkbox}]`);
1149
+ if (selectionCheckbox) {
1150
+ const isHeader = selectionCheckbox.hasAttribute(tableControls.checkbox.attributes.header);
1151
+ if (isHeader) {
1152
+ if (this._selection.allRowsSeleted.value) {
1153
+ this._selection.setSelection("none");
1154
+ } else {
1155
+ this._selection.setSelection("all");
1156
+ }
1157
+ } else {
1158
+ const rowIndex = Number(selectionCheckbox.getAttribute(tableControls.checkbox.attributes.checkbox));
1159
+ this._selection.toggleSelectionForRowIndex(rowIndex);
1160
+ }
1386
1161
  }
1387
1162
  }
1388
1163
  };
1164
+ this._table = table;
1165
+ this._projection = projection;
1166
+ this._sorting.value = sorting.at(0);
1167
+ this._pinnedRows = pinnedRows;
1168
+ this._onInsertRow = onInsertRow;
1169
+ this._onDeleteRows = onDeleteRows;
1170
+ this._onDeleteColumn = onDeleteColumn;
1171
+ this._onCellUpdate = onCellUpdate;
1172
+ this._onRowOrderChanged = onRowOrderChanged;
1389
1173
  }
1390
- };
1391
-
1392
- // packages/ui/react-ui-table/src/schema/column-utils.ts
1393
- import { FieldValueType, mapSchemaToFields } from "@dxos/schema";
1394
- var schemaToColumnDefs = (schema) => {
1395
- const { helper, builder } = createColumnBuilder();
1396
- const classified = mapSchemaToFields(schema);
1397
- return classified.map(([name, type]) => {
1398
- const propertyKey = name.toString();
1399
- let column;
1400
- switch (type) {
1401
- case FieldValueType.String: {
1402
- column = builder.string({
1403
- label: propertyKey,
1404
- classNames: [
1405
- name === "id" && "font-mono"
1406
- ]
1407
- });
1408
- break;
1174
+ get table() {
1175
+ return this._table;
1176
+ }
1177
+ get projection() {
1178
+ return this._projection;
1179
+ }
1180
+ get pinnedRows() {
1181
+ return this._pinnedRows;
1182
+ }
1183
+ get columnMeta() {
1184
+ invariant3(this._columnMeta, void 0, {
1185
+ F: __dxlog_file4,
1186
+ L: 124,
1187
+ S: this,
1188
+ A: [
1189
+ "this._columnMeta",
1190
+ ""
1191
+ ]
1192
+ });
1193
+ return this._columnMeta;
1194
+ }
1195
+ get sorting() {
1196
+ return this._sorting.value;
1197
+ }
1198
+ get modalController() {
1199
+ return this._modalController;
1200
+ }
1201
+ get selection() {
1202
+ return this._selection;
1203
+ }
1204
+ //
1205
+ // Initialisation
1206
+ //
1207
+ async _open() {
1208
+ this.initializeColumnMeta();
1209
+ this.initializeSorting();
1210
+ this.initializeEffects();
1211
+ this._selection = new SelectionModel(this._sortedRows, () => this._onRowOrderChanged?.());
1212
+ await this._selection.open(this._ctx);
1213
+ }
1214
+ initializeColumnMeta() {
1215
+ this._columnMeta = computed2(() => {
1216
+ const fields = this._table.view?.fields ?? [];
1217
+ const meta = Object.fromEntries(fields.map((field, index) => [
1218
+ index,
1219
+ {
1220
+ size: field?.size ?? 256,
1221
+ resizeable: true
1222
+ }
1223
+ ]));
1224
+ return {
1225
+ grid: meta,
1226
+ frozenColsStart: {
1227
+ 0: {
1228
+ size: 30,
1229
+ resizeable: false
1230
+ }
1231
+ },
1232
+ frozenColsEnd: {
1233
+ 0: {
1234
+ size: 40,
1235
+ resizeable: false
1236
+ }
1237
+ }
1238
+ };
1239
+ });
1240
+ }
1241
+ initializeSorting() {
1242
+ this._sortedRows = computed2(() => {
1243
+ this._displayToDataIndex.clear();
1244
+ const sort = this._sorting.value;
1245
+ if (!sort) {
1246
+ return this._rows.value;
1409
1247
  }
1410
- case FieldValueType.Number: {
1411
- column = builder.number({
1412
- label: propertyKey
1413
- });
1414
- break;
1248
+ const field = this._table.view?.fields.find((field2) => field2.id === sort.fieldId);
1249
+ if (!field) {
1250
+ return this._rows.value;
1415
1251
  }
1416
- case FieldValueType.Boolean: {
1417
- column = builder.switch({
1418
- label: propertyKey
1419
- });
1420
- break;
1252
+ const dataWithIndices = this._rows.value.map((item, index) => {
1253
+ const value = getValue2(item, field.path);
1254
+ return {
1255
+ item,
1256
+ index,
1257
+ value,
1258
+ isEmpty: value == null || value === ""
1259
+ };
1260
+ });
1261
+ const sorted = orderBy(dataWithIndices, [
1262
+ "isEmpty",
1263
+ "value"
1264
+ ], [
1265
+ "asc",
1266
+ sort.direction
1267
+ ]);
1268
+ for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
1269
+ const { index: dataIndex } = sorted[displayIndex];
1270
+ if (displayIndex !== dataIndex) {
1271
+ this._displayToDataIndex.set(displayIndex, dataIndex);
1272
+ }
1421
1273
  }
1422
- case FieldValueType.Date: {
1423
- column = builder.date({
1424
- label: propertyKey
1425
- });
1426
- break;
1274
+ return sorted.map(({ item }) => item);
1275
+ });
1276
+ }
1277
+ initializeEffects() {
1278
+ const rowOrderWatcher = effect2(() => {
1279
+ touch(this._sortedRows.value);
1280
+ this._onRowOrderChanged?.();
1281
+ });
1282
+ this._ctx.onDispose(rowOrderWatcher);
1283
+ const rowEffectManager = effect2(() => {
1284
+ const { start, end } = touch(this._visibleRange.value);
1285
+ const rowEffects = [];
1286
+ for (let row = start.row; row <= end.row; row++) {
1287
+ rowEffects.push(effect2(() => {
1288
+ const obj = this._sortedRows.value[row];
1289
+ this?._table?.view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
1290
+ this._onCellUpdate?.({
1291
+ row,
1292
+ col: start.col
1293
+ });
1294
+ }));
1427
1295
  }
1428
- case FieldValueType.JSON: {
1429
- column = builder.json({
1430
- label: propertyKey,
1431
- id: propertyKey
1432
- });
1433
- break;
1296
+ return () => rowEffects.forEach((cleanup) => cleanup());
1297
+ });
1298
+ this._ctx.onDispose(rowEffectManager);
1299
+ }
1300
+ //
1301
+ // Column Operations
1302
+ //
1303
+ deleteColumn(fieldId) {
1304
+ if (!this.table.view) {
1305
+ return;
1306
+ }
1307
+ const field = this.table.view.fields.find((field2) => field2.id === fieldId);
1308
+ if (field && this._onDeleteColumn) {
1309
+ if (this._sorting.value?.fieldId === fieldId) {
1310
+ this.clearSort();
1434
1311
  }
1435
- default: {
1436
- throw new Error(`Unhandled column type: ${type}`);
1312
+ this._onDeleteColumn(field.id);
1313
+ }
1314
+ }
1315
+ //
1316
+ // Resize
1317
+ //
1318
+ setColumnWidth(columnIndex, width) {
1319
+ const fields = this.table.view?.fields ?? [];
1320
+ if (columnIndex < fields.length) {
1321
+ const newWidth = Math.max(0, width);
1322
+ const field = fields[columnIndex];
1323
+ if (field) {
1324
+ field.size = newWidth;
1437
1325
  }
1438
1326
  }
1439
- return helper.accessor(propertyKey, column);
1440
- });
1327
+ }
1328
+ //
1329
+ // Sorting
1330
+ //
1331
+ setSort(fieldId, direction) {
1332
+ this._sorting.value = {
1333
+ fieldId,
1334
+ direction
1335
+ };
1336
+ }
1337
+ clearSort() {
1338
+ this._sorting.value = void 0;
1339
+ }
1340
+ //
1341
+ // Pinning
1342
+ //
1343
+ // TODO(burdon): Change to setPinned(on/off).
1344
+ pinRow(rowIndex, side) {
1345
+ this._pinnedRows[side].push(rowIndex);
1346
+ }
1347
+ unpinRow(rowIndex) {
1348
+ this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
1349
+ this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
1350
+ }
1351
+ };
1352
+
1353
+ // packages/ui/react-ui-table/src/hooks/useTableModel.ts
1354
+ var useTableModel = ({ objects, table, projection, ...props }) => {
1355
+ const [model, setModel] = useState3();
1356
+ useEffect2(() => {
1357
+ if (!table || !projection) {
1358
+ return;
1359
+ }
1360
+ let model2;
1361
+ const t = setTimeout(async () => {
1362
+ model2 = new TableModel({
1363
+ table,
1364
+ projection,
1365
+ ...props
1366
+ });
1367
+ await model2.open();
1368
+ setModel(model2);
1369
+ });
1370
+ return () => {
1371
+ clearTimeout(t);
1372
+ void model2?.close();
1373
+ };
1374
+ }, [
1375
+ table,
1376
+ projection
1377
+ ]);
1378
+ useEffect2(() => {
1379
+ if (objects) {
1380
+ model?.setRows(objects);
1381
+ }
1382
+ }, [
1383
+ model,
1384
+ objects
1385
+ ]);
1386
+ return model;
1441
1387
  };
1442
1388
  export {
1443
- CellCombobox,
1444
- ColumnBuilder,
1445
- ColumnMenu,
1446
- ColumnSettings,
1447
- MemoizedVirtualizedTableContent,
1448
- SortIndicator,
1449
- TABLE_NAME,
1450
1389
  Table,
1451
- TablePrimitive,
1452
- TableProvider,
1453
- TableRootContext,
1454
- createColumnBuilder,
1455
- currentRow,
1456
- flushPadding,
1457
- gridCellFocusRing,
1458
- groupTh,
1459
- headPadding,
1460
- schemaToColumnDefs,
1461
- selectedRow,
1462
- tableRoot,
1463
- tbodyRoot,
1464
- tbodyTr,
1465
- tdRoot,
1466
- textPadding,
1467
- theadResizeRoot,
1468
- theadRoot,
1469
- theadTh,
1470
- theadTr,
1390
+ TableType,
1391
+ Toolbar,
1392
+ fromGridCell,
1393
+ initializeTable,
1394
+ tableButtons,
1395
+ toGridCell,
1396
+ touch,
1471
1397
  translations_default as translations,
1472
- useColumnResizing,
1473
- useColumnSorting,
1474
- usePinLastRow,
1475
- useRowSelection,
1476
- useSortColumn,
1477
- useTableContext,
1478
- useTableRootContext
1398
+ useTableModel,
1399
+ useToolbarContext
1479
1400
  };
1480
1401
  //# sourceMappingURL=index.mjs.map