@dxos/react-ui-table 0.6.14-staging.e15392e → 0.7.1-staging.599df14

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