@dxos/react-ui-table 0.8.4-main.c1de068 → 0.8.4-main.c85a9c8dae

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 (158) hide show
  1. package/dist/lib/browser/chunk-DSR2MRZB.mjs +80 -0
  2. package/dist/lib/browser/chunk-DSR2MRZB.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-PTHMYAAM.mjs +1751 -0
  4. package/dist/lib/browser/chunk-PTHMYAAM.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +1190 -1139
  6. package/dist/lib/browser/index.mjs.map +4 -4
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/testing/index.mjs +31 -38
  9. package/dist/lib/browser/testing/index.mjs.map +3 -3
  10. package/dist/lib/browser/types/index.mjs +3 -3
  11. package/dist/lib/node-esm/chunk-GI72MQSG.mjs +1753 -0
  12. package/dist/lib/node-esm/chunk-GI72MQSG.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-HTZJSULI.mjs +81 -0
  14. package/dist/lib/node-esm/chunk-HTZJSULI.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1190 -1139
  16. package/dist/lib/node-esm/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/testing/index.mjs +31 -38
  19. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/types/index.mjs +3 -3
  21. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -3
  22. package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
  23. package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -3
  24. package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
  25. package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
  26. package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
  27. package/dist/types/src/components/Table/DynamicTable.stories.d.ts +37 -3
  28. package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Table/Relations.stories.d.ts +111 -0
  30. package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
  31. package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
  32. package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
  33. package/dist/types/src/components/Table/Table.d.ts +17 -13
  34. package/dist/types/src/components/Table/Table.d.ts.map +1 -1
  35. package/dist/types/src/components/Table/Table.stories.d.ts +108 -4
  36. package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +1 -1
  38. package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
  39. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +13 -9
  40. package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
  41. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +11 -18
  42. package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
  43. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +39 -4
  44. package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
  46. package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
  47. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +5 -5
  48. package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -1
  49. package/dist/types/src/components/testing.d.ts +23 -16
  50. package/dist/types/src/components/testing.d.ts.map +1 -1
  51. package/dist/types/src/hooks/index.d.ts +2 -1
  52. package/dist/types/src/hooks/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/useAddRow.d.ts +6 -6
  54. package/dist/types/src/hooks/useAddRow.d.ts.map +1 -1
  55. package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
  56. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useTableModel.d.ts +10 -10
  58. package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
  59. package/dist/types/src/model/modal-controller.d.ts +5 -8
  60. package/dist/types/src/model/modal-controller.d.ts.map +1 -1
  61. package/dist/types/src/model/selection-model.d.ts +17 -8
  62. package/dist/types/src/model/selection-model.d.ts.map +1 -1
  63. package/dist/types/src/model/table-model.d.ts +112 -30
  64. package/dist/types/src/model/table-model.d.ts.map +1 -1
  65. package/dist/types/src/model/table-presentation.d.ts +5 -2
  66. package/dist/types/src/model/table-presentation.d.ts.map +1 -1
  67. package/dist/types/src/playwright/TableManager.d.ts +2 -1
  68. package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
  69. package/dist/types/src/testing/useTestTableModel.d.ts +18 -34
  70. package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -1
  71. package/dist/types/src/translations.d.ts +4 -4
  72. package/dist/types/src/translations.d.ts.map +1 -1
  73. package/dist/types/src/types/Table.d.ts +31 -0
  74. package/dist/types/src/types/Table.d.ts.map +1 -0
  75. package/dist/types/src/types/index.d.ts +1 -1
  76. package/dist/types/src/types/index.d.ts.map +1 -1
  77. package/dist/types/src/util/dynamic-table.d.ts +14 -12
  78. package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
  79. package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
  80. package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
  81. package/dist/types/src/util/index.d.ts +2 -1
  82. package/dist/types/src/util/index.d.ts.map +1 -1
  83. package/dist/types/src/util/query-ast.d.ts +7 -0
  84. package/dist/types/src/util/query-ast.d.ts.map +1 -0
  85. package/dist/types/src/util/schema.d.ts +1 -1
  86. package/dist/types/src/util/schema.d.ts.map +1 -1
  87. package/dist/types/src/util/sort.d.ts +12 -0
  88. package/dist/types/src/util/sort.d.ts.map +1 -0
  89. package/dist/types/src/util/table-buttons.d.ts.map +1 -1
  90. package/dist/types/src/util/table-controls.d.ts.map +1 -1
  91. package/dist/types/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +61 -56
  93. package/src/components/Table/ColumnActionsMenu.tsx +11 -7
  94. package/src/components/Table/ColumnSettings.tsx +9 -10
  95. package/src/components/Table/DynamicTable.stories.tsx +28 -24
  96. package/src/components/Table/DynamicTable.tsx +33 -27
  97. package/src/components/Table/Relations.stories.tsx +240 -0
  98. package/src/components/Table/RowActionsMenu.tsx +26 -17
  99. package/src/components/Table/Table.stories.tsx +146 -116
  100. package/src/components/Table/Table.tsx +353 -297
  101. package/src/components/TableCellEditor/CellValidationMessage.tsx +6 -6
  102. package/src/components/TableCellEditor/FormCellEditor.tsx +134 -40
  103. package/src/components/TableCellEditor/TableCellEditor.stories.tsx +31 -66
  104. package/src/components/TableCellEditor/TableCellEditor.tsx +88 -238
  105. package/src/components/TableCellEditor/index.ts +1 -0
  106. package/src/components/TableToolbar/TableToolbar.tsx +54 -38
  107. package/src/components/testing.ts +39 -13
  108. package/src/hooks/index.ts +2 -1
  109. package/src/hooks/useAddRow.ts +14 -14
  110. package/src/hooks/useProjectionModel.ts +39 -0
  111. package/src/hooks/useTableModel.ts +36 -34
  112. package/src/model/modal-controller.ts +24 -41
  113. package/src/model/selection-model.ts +75 -43
  114. package/src/model/table-model.test.ts +92 -55
  115. package/src/model/table-model.ts +453 -175
  116. package/src/model/table-presentation.test.ts +70 -58
  117. package/src/model/table-presentation.ts +111 -64
  118. package/src/playwright/TableManager.ts +13 -6
  119. package/src/playwright/playwright.config.ts +1 -1
  120. package/src/playwright/smoke.spec.ts +171 -33
  121. package/src/testing/useTestTableModel.ts +46 -35
  122. package/src/translations.ts +3 -3
  123. package/src/types/Table.ts +95 -0
  124. package/src/types/index.ts +1 -1
  125. package/src/util/dynamic-table.test.ts +70 -0
  126. package/src/util/dynamic-table.ts +46 -33
  127. package/src/util/index.ts +2 -1
  128. package/src/util/query-ast.ts +22 -0
  129. package/src/util/schema.ts +4 -4
  130. package/src/util/sort.ts +90 -0
  131. package/src/util/table-buttons.ts +4 -3
  132. package/src/util/table-controls.ts +6 -3
  133. package/dist/lib/browser/chunk-5XLSHLOG.mjs +0 -1751
  134. package/dist/lib/browser/chunk-5XLSHLOG.mjs.map +0 -7
  135. package/dist/lib/browser/chunk-L2LSB6KV.mjs +0 -18
  136. package/dist/lib/browser/chunk-L2LSB6KV.mjs.map +0 -7
  137. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs +0 -20
  138. package/dist/lib/node-esm/chunk-NXZ4CJYX.mjs.map +0 -7
  139. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs +0 -1752
  140. package/dist/lib/node-esm/chunk-Y66YLSTC.mjs.map +0 -7
  141. package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
  142. package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
  143. package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
  144. package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
  145. package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
  146. package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
  147. package/dist/types/src/model/table-sorting.d.ts +0 -53
  148. package/dist/types/src/model/table-sorting.d.ts.map +0 -1
  149. package/dist/types/src/types/schema.d.ts +0 -8
  150. package/dist/types/src/types/schema.d.ts.map +0 -1
  151. package/dist/types/src/util/table.d.ts +0 -11
  152. package/dist/types/src/util/table.d.ts.map +0 -1
  153. package/src/components/Table/CreateRefPanel.tsx +0 -86
  154. package/src/components/Table/relations.stories.tsx +0 -116
  155. package/src/components/TableCellEditor/extension.ts +0 -61
  156. package/src/model/table-sorting.ts +0 -216
  157. package/src/types/schema.ts +0 -16
  158. package/src/util/table.ts +0 -49
@@ -2,25 +2,27 @@ import {
2
2
  BUTTON_IDENTIFIERS,
3
3
  CONTROL_IDENTIFIERS,
4
4
  CheckboxStory,
5
- ModalController,
6
5
  SwitchStory,
7
6
  TableModel,
8
7
  TablePresentation,
9
8
  cellClassesForRowSelection,
10
- createTable,
11
- getBaseSchema,
12
- makeDynamicTable,
13
- narrowSchema,
9
+ compareValues,
10
+ createDirectChangeCallback,
11
+ createEchoChangeCallback,
12
+ extractOrder,
13
+ getSortValue,
14
14
  tableButtons,
15
15
  tableControls,
16
- touch,
17
16
  useAddRow,
17
+ useProjectionModel,
18
18
  useTableModel
19
- } from "./chunk-5XLSHLOG.mjs";
20
- import "./chunk-L2LSB6KV.mjs";
19
+ } from "./chunk-PTHMYAAM.mjs";
20
+ import {
21
+ Table_exports
22
+ } from "./chunk-DSR2MRZB.mjs";
21
23
 
22
24
  // src/translations.ts
23
- var translationKey = "react-ui-table";
25
+ var translationKey = "@dxos/react-ui-table";
24
26
  var translations = [
25
27
  {
26
28
  "en-US": {
@@ -29,8 +31,8 @@ var translations = [
29
31
  "create object label": "Create table",
30
32
  "table name placeholder": "Table name",
31
33
  "settings title": "Table settings",
32
- "table schema label": "Schema",
33
- "new schema": "New schema",
34
+ "table schema label": "Type",
35
+ "new schema": "New type",
34
36
  "continue label": "Continue",
35
37
  "create stack section label": "Create table",
36
38
  "add row label": "Add row",
@@ -52,333 +54,284 @@ var translations = [
52
54
  ];
53
55
 
54
56
  // src/components/Table/Table.tsx
55
- import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
56
- import React8, { forwardRef, useCallback as useCallback5, useImperativeHandle, useState as useState4, useMemo as useMemo5, useEffect as useEffect4 } from "react";
57
- import { Filter } from "@dxos/echo";
58
- import { getValue } from "@dxos/echo-schema";
59
- import { invariant as invariant3 } from "@dxos/invariant";
60
- import { getSpace as getSpace2 } from "@dxos/react-client/echo";
61
- import { useTranslation as useTranslation3 } from "@dxos/react-ui";
57
+ import { Atom as Atom3, RegistryContext as RegistryContext2, useAtomValue as useAtomValue4 } from "@effect-atom/atom-react";
58
+ import * as String2 from "effect/String";
59
+ import React8, { forwardRef, useCallback as useCallback4, useContext as useContext2, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo5, useState as useState4 } from "react";
60
+ import { log } from "@dxos/log";
62
61
  import { useAttention } from "@dxos/react-ui-attention";
63
- import { closestCell, Grid, gridSeparatorInlineEnd, gridSeparatorBlockEnd } from "@dxos/react-ui-grid";
64
- import { mx } from "@dxos/react-ui-theme";
65
- import { isNotFalsy, safeParseInt } from "@dxos/util";
62
+ import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
63
+ import { DxEditRequest } from "@dxos/react-ui-grid";
64
+ import { mx, useComposableProps } from "@dxos/ui-theme";
66
65
 
67
- // src/components/Table/ColumnActionsMenu.tsx
68
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
69
- import React from "react";
70
- import { DropdownMenu, useTranslation } from "@dxos/react-ui";
71
- var ColumnActionsMenu = ({ model, modals }) => {
72
- var _effect = _useSignals();
73
- try {
74
- const { t } = useTranslation(translationKey);
75
- const state = modals.state.value;
76
- if (state?.type !== "column") {
77
- return null;
66
+ // src/util/dynamic-table.ts
67
+ import { Filter, JsonSchema, Obj, Order, Query, Ref, Type } from "@dxos/echo";
68
+ import { ProjectionModel, ViewModel, createEchoChangeCallback as createEchoChangeCallback2, getSchemaFromPropertyDefinitions } from "@dxos/schema";
69
+ var getBaseSchema = ({ schema, typename, properties, jsonSchema }) => {
70
+ if (typename && properties) {
71
+ const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
72
+ return {
73
+ typename: schema2.typename,
74
+ jsonSchema: JsonSchema.toJsonSchema(schema2)
75
+ };
76
+ } else if (schema) {
77
+ return {
78
+ typename: Type.getTypename(schema),
79
+ jsonSchema: JsonSchema.toJsonSchema(schema)
80
+ };
81
+ } else if (typename && jsonSchema) {
82
+ return {
83
+ typename,
84
+ jsonSchema
85
+ };
86
+ } else {
87
+ throw new Error("invalid properties");
88
+ }
89
+ };
90
+ var makeDynamicTable = ({ registry, jsonSchema, properties }) => {
91
+ const view = ViewModel.make({
92
+ query: Query.select(Filter.everything()),
93
+ jsonSchema,
94
+ ...properties && {
95
+ fields: properties.map((property) => property.name)
78
96
  }
79
- const currentSort = model.sorting?.sorting;
80
- const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
81
- return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
82
- modal: false,
83
- open: true,
84
- onOpenChange: modals.close
85
- }, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
86
- virtualRef: modals.trigger
87
- }), /* @__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, {
88
- "data-testid": "column-sort-descending",
89
- onClick: () => model.sorting?.setSort(state.fieldId, "desc")
90
- }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
91
- "data-testid": "column-sort-ascending",
92
- onClick: () => model.sorting?.setSort(state.fieldId, "asc")
93
- }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
94
- "data-testid": "column-clear-sort",
95
- onClick: () => model.sorting?.clearSort()
96
- }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
97
- "data-testid": "column-delete",
98
- onClick: () => model.deleteColumn(state.fieldId)
99
- }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
100
- "data-testid": "column-settings",
101
- onClick: () => modals.openColumnSettings()
102
- }, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
103
- } finally {
104
- _effect.f();
97
+ });
98
+ const object = Obj.make(Table_exports.Table, {
99
+ view: Ref.make(view),
100
+ sizes: {}
101
+ });
102
+ const projection = new ProjectionModel({
103
+ registry,
104
+ view,
105
+ baseSchema: jsonSchema,
106
+ change: createEchoChangeCallback2(view, jsonSchema)
107
+ });
108
+ projection.normalizeView();
109
+ if (properties && projection.getFields()) {
110
+ setProperties(view, projection, object, properties);
105
111
  }
112
+ return {
113
+ projection,
114
+ object
115
+ };
106
116
  };
107
-
108
- // src/components/Table/ColumnSettings.tsx
109
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
110
- import React2, { useCallback, useEffect, useMemo, useState } from "react";
111
- import { Popover } from "@dxos/react-ui";
112
- import { FieldEditor } from "@dxos/react-ui-form";
113
- var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
114
- var _effect = _useSignals2();
115
- try {
116
- const [newField, setNewField] = useState();
117
- const state = modals.state.value;
118
- useEffect(() => {
119
- if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
120
- setNewField(model.projection.createFieldProjection());
121
- requestAnimationFrame(() => {
122
- onNewColumn();
117
+ var setProperties = (view, projection, table, properties) => {
118
+ for (const property of properties) {
119
+ const field = projection.getFields().find((field2) => field2.path === property.name);
120
+ if (field) {
121
+ if (property.size !== void 0) {
122
+ Obj.change(table, (t) => {
123
+ t.sizes[field.path] = property.size;
123
124
  });
124
- } else {
125
- setNewField(void 0);
126
125
  }
127
- }, [
128
- model?.projection,
129
- state
130
- ]);
131
- const existingField = useMemo(() => {
132
- if (state?.type === "columnSettings") {
133
- const { mode } = state;
134
- if (mode.type === "edit") {
135
- return model?.projection?.fields.find((f) => f.id === mode.fieldId);
136
- }
126
+ if (property.title !== void 0) {
127
+ const fieldProjection = projection.getFieldProjection(field.id);
128
+ projection.setFieldProjection({
129
+ ...fieldProjection,
130
+ props: {
131
+ ...fieldProjection.props,
132
+ title: property.title
133
+ }
134
+ });
137
135
  }
138
- return void 0;
139
- }, [
140
- model?.projection?.fields,
141
- state
142
- ]);
143
- const field = existingField ?? newField;
144
- const handleSave = useCallback(() => {
145
- modals.close();
146
- }, [
147
- modals
148
- ]);
149
- const handleCancel = useCallback(() => {
150
- if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
151
- model?.projection.deleteFieldProjection(newField.id);
136
+ if (property.sort) {
137
+ const currentQuery = Query.fromAst(Obj.getSnapshot(view).query.ast);
138
+ const newQuery = currentQuery.orderBy(Order.property(field.path, property.sort));
139
+ Obj.change(view, (v) => {
140
+ v.query.ast = newQuery.ast;
141
+ });
152
142
  }
153
- }, [
154
- model?.projection,
155
- state,
156
- newField
157
- ]);
158
- if (!model?.projection || !field) {
159
- return null;
160
143
  }
161
- return /* @__PURE__ */ React2.createElement(Popover.Root, {
162
- modal: false,
163
- open: state?.type === "columnSettings"
164
- }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
165
- virtualRef: modals.trigger
166
- }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
167
- classNames: "md:is-64"
168
- }, /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
169
- projection: model.projection,
170
- field,
171
- registry,
172
- onSave: handleSave,
173
- onCancel: handleCancel
174
- })), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
175
- } finally {
176
- _effect.f();
177
144
  }
178
145
  };
179
146
 
180
- // src/components/Table/CreateRefPanel.tsx
181
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
182
- import { Schema } from "effect";
183
- import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
184
- import { live } from "@dxos/live-object";
185
- import { getSpace } from "@dxos/react-client/echo";
186
- import { Popover as Popover2 } from "@dxos/react-ui";
187
- import { Form } from "@dxos/react-ui-form";
188
- import { useGridContext } from "@dxos/react-ui-grid";
189
- var CreateRefPanel = ({ model, modals, __gridScope }) => {
190
- var _effect = _useSignals3();
191
- try {
192
- const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
193
- const space = model && getSpace(model?.view);
194
- const state = modals.state.value;
195
- const schema = useMemo2(() => {
196
- if (!space || state?.type !== "createRefPanel") {
197
- return;
198
- }
199
- const [schema2] = space.db.schemaRegistry.query({
200
- typename: state.typename
201
- }).runSync();
202
- if (schema2) {
203
- const omit = Schema.omit("id");
204
- return omit(schema2);
205
- }
206
- }, [
207
- space,
208
- state
209
- ]);
210
- const handleSave = useCallback2((values) => {
211
- if (!model || !space || state?.type !== "createRefPanel") {
212
- return;
213
- }
214
- const [schema2] = space.db.schemaRegistry.query({
215
- typename: state.typename
216
- }).runSync();
217
- if (schema2) {
218
- const obj = space.db.add(live(schema2, values));
219
- state.onCreate?.(obj);
220
- }
221
- void modals.close();
222
- }, [
223
- modals,
224
- space,
225
- state
226
- ]);
227
- const handleCancel = useCallback2(() => {
228
- if (model) {
229
- modals.close();
230
- }
231
- }, [
232
- modals
233
- ]);
234
- if (!model?.projection) {
235
- return null;
147
+ // src/util/signals.ts
148
+ var touch = (value) => value;
149
+
150
+ // src/util/schema.ts
151
+ import * as Schema from "effect/Schema";
152
+ import * as SchemaAST from "effect/SchemaAST";
153
+ var narrowSchema = (schema, paths) => {
154
+ const ast = schema?.ast;
155
+ if (SchemaAST.isTypeLiteral(ast)) {
156
+ const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
157
+ if (propertySignatures.length > 0) {
158
+ const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
159
+ return Schema.make(narrowType);
236
160
  }
237
- return /* @__PURE__ */ React3.createElement(Popover2.Root, {
238
- modal: false,
239
- open: state?.type === "createRefPanel" && !!schema,
240
- onOpenChange: (nextOpen) => {
241
- if (model && !nextOpen) {
242
- return modals.close();
243
- }
244
- }
245
- }, /* @__PURE__ */ React3.createElement(Popover2.VirtualTrigger, {
246
- virtualRef: modals.trigger
247
- }), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
248
- classNames: "md:is-64",
249
- "data-grid": gridId
250
- }, /* @__PURE__ */ React3.createElement(Popover2.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React3.createElement(Form, {
251
- schema,
252
- values: state.initialValues ?? {},
253
- onSave: handleSave,
254
- onCancel: handleCancel
255
- })), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null))));
256
- } finally {
257
- _effect.f();
258
161
  }
162
+ return void 0;
259
163
  };
260
164
 
261
- // src/components/Table/RowActionsMenu.tsx
262
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
263
- import React4 from "react";
264
- import { DropdownMenu as DropdownMenu2, useTranslation as useTranslation2 } from "@dxos/react-ui";
265
- var RowActionsMenu = ({ model, modals }) => {
266
- var _effect = _useSignals4();
267
- try {
268
- const { t } = useTranslation2(translationKey);
269
- const hasSelection = model.selection.hasSelection.value;
270
- const state = modals.state.value;
271
- if (state?.type !== "row") {
272
- return null;
273
- }
274
- return /* @__PURE__ */ React4.createElement(DropdownMenu2.Root, {
275
- modal: false,
276
- open: true,
277
- onOpenChange: modals.close
278
- }, /* @__PURE__ */ React4.createElement(DropdownMenu2.VirtualTrigger, {
279
- virtualRef: modals.trigger
280
- }), /* @__PURE__ */ React4.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
281
- "data-testid": "row-menu-delete",
282
- onClick: () => model.deleteRow(state.rowIndex)
283
- }, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
284
- key: action.id,
285
- "data-testid": `row-action-${action.id}`,
286
- onClick: () => {
287
- modals.close();
288
- model.handleRowAction(action.id, state.rowIndex);
289
- }
290
- }, t(action.translationKey)))), /* @__PURE__ */ React4.createElement(DropdownMenu2.Arrow, null)));
291
- } finally {
292
- _effect.f();
165
+ // src/model/modal-controller.ts
166
+ import { Atom } from "@effect-atom/atom-react";
167
+ var ModalController = class {
168
+ _registry;
169
+ _state;
170
+ _triggerRef = {
171
+ current: null
172
+ };
173
+ constructor(registry) {
174
+ this._registry = registry;
175
+ this._state = Atom.make({
176
+ type: "closed"
177
+ });
178
+ }
179
+ get state() {
180
+ return this._state;
181
+ }
182
+ get stateValue() {
183
+ return this._registry.get(this._state);
293
184
  }
185
+ get trigger() {
186
+ return this._triggerRef;
187
+ }
188
+ setTrigger = (trigger) => {
189
+ this._triggerRef.current = trigger;
190
+ };
191
+ showRowMenu = (rowIndex) => {
192
+ this._registry.set(this._state, {
193
+ type: "row",
194
+ rowIndex
195
+ });
196
+ };
197
+ showColumnMenu = (fieldId) => {
198
+ this._registry.set(this._state, {
199
+ type: "column",
200
+ fieldId
201
+ });
202
+ };
203
+ showColumnCreator = () => {
204
+ this._registry.set(this._state, {
205
+ type: "columnSettings",
206
+ mode: {
207
+ type: "create"
208
+ }
209
+ });
210
+ };
211
+ showReferencePanel = (targetId, schemaId) => {
212
+ this._registry.set(this._state, {
213
+ type: "refPanel",
214
+ targetId,
215
+ typename: schemaId
216
+ });
217
+ };
218
+ openColumnSettings = () => {
219
+ const currentState = this._registry.get(this._state);
220
+ if (currentState.type === "column") {
221
+ const fieldId = currentState.fieldId;
222
+ requestAnimationFrame(() => {
223
+ this._registry.set(this._state, {
224
+ type: "columnSettings",
225
+ mode: {
226
+ type: "edit",
227
+ fieldId
228
+ }
229
+ });
230
+ });
231
+ }
232
+ };
233
+ close = () => {
234
+ this._registry.set(this._state, {
235
+ type: "closed"
236
+ });
237
+ };
294
238
  };
295
239
 
296
240
  // src/components/TableCellEditor/TableCellEditor.tsx
297
- import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
298
- import React7, { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef2, useState as useState3 } from "react";
299
- import { FormatEnum, TypeEnum } from "@dxos/echo-schema";
241
+ import { EditorView } from "@codemirror/view";
242
+ import React3, { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
243
+ import { debounce } from "@dxos/async";
244
+ import { Format, TypeEnum } from "@dxos/echo/internal";
300
245
  import { invariant as invariant2 } from "@dxos/invariant";
301
- import { useThemeContext } from "@dxos/react-ui";
302
- import { createMarkdownExtensions } from "@dxos/react-ui-editor";
303
- import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext4, GridCellEditor } from "@dxos/react-ui-grid";
304
- import { tagPicker, createLinks } from "@dxos/react-ui-tag-picker";
246
+ import { GridCellEditor, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
305
247
 
306
248
  // src/components/TableCellEditor/CellValidationMessage.tsx
307
- import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
308
- import React5 from "react";
309
- import { useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
310
- var CellValidationMessage = ({ validationError, variant = "error", __gridScope }) => {
311
- var _effect = _useSignals5();
312
- try {
313
- const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
314
- if (!editing || !validationError) {
315
- return null;
316
- }
317
- const bgClass = variant === "error" ? "bg-errorSurface" : "bg-warningSurface";
318
- const textClass = variant === "error" ? "text-errorSurfaceText" : "text-warningSurfaceText";
319
- return /* @__PURE__ */ React5.createElement("div", {
320
- role: "none",
321
- className: `absolute ${bgClass} ${textClass} rounded-bs-sm text-xs p-1`,
322
- style: {
323
- ...{
324
- "--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
325
- },
326
- zIndex: 10,
327
- insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
328
- insetInlineStart: box.insetInlineStart,
329
- inlineSize: box.inlineSize
330
- }
331
- }, validationError);
332
- } finally {
333
- _effect.f();
249
+ import React from "react";
250
+ import { useGridContext } from "@dxos/react-ui-grid";
251
+ var CellValidationMessage = ({ __gridScope, validationError, variant = "error" }) => {
252
+ const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
253
+ if (!editing || !validationError) {
254
+ return null;
334
255
  }
256
+ const bgClass = variant === "error" ? "bg-error-surface" : "bg-warning-surface";
257
+ const textClass = variant === "error" ? "text-error-surface-text" : "text-warning-surface-text";
258
+ return /* @__PURE__ */ React.createElement("div", {
259
+ role: "none",
260
+ className: `absolute ${bgClass} ${textClass} rounded-h-sm text-xs p-1`,
261
+ style: {
262
+ ...{
263
+ "--dx-grid-cell-width": `${box?.inlineSize ?? 200}px`
264
+ },
265
+ zIndex: 10,
266
+ insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
267
+ insetInlineStart: box.insetInlineStart,
268
+ inlineSize: box.inlineSize
269
+ }
270
+ }, validationError);
335
271
  };
336
272
 
337
273
  // src/components/TableCellEditor/FormCellEditor.tsx
338
- import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
339
- import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef, useState as useState2 } from "react";
340
- import { getSnapshot } from "@dxos/echo-schema";
274
+ import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
275
+ import { Entity } from "@dxos/echo";
276
+ import { Ref as Ref2, getValue } from "@dxos/echo/internal";
341
277
  import { invariant } from "@dxos/invariant";
342
- import { Popover as Popover3 } from "@dxos/react-ui";
343
- import { Form as Form2 } from "@dxos/react-ui-form";
344
- import { parseCellIndex, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
345
- import { getDeep, setDeep } from "@dxos/util";
278
+ import { Popover } from "@dxos/react-ui";
279
+ import { Form } from "@dxos/react-ui-form";
280
+ import { parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
281
+ import { getDeep, isTruthy, setDeep } from "@dxos/util";
346
282
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
347
- var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) => {
348
- var _effect = _useSignals6();
349
- try {
350
- const { editing: contextEditing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
351
- const [editing, setLocalEditing] = useState2(false);
352
- const anchorRef = useRef(null);
353
- useEffect2(() => {
354
- if (contextEditing && contextEditing.cellElement) {
355
- anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
356
- setLocalEditing(true);
357
- } else {
358
- anchorRef.current = null;
359
- setLocalEditing(false);
360
- }
361
- }, [
362
- contextEditing
363
- ]);
364
- const narrowedSchema = useMemo3(() => {
365
- if (!schema) {
366
- return void 0;
367
- }
368
- return narrowSchema(schema, [
369
- fieldProjection.field.path
370
- ]);
371
- }, [
372
- JSON.stringify(schema),
283
+ var createOptionLabel = [
284
+ "create new object label",
285
+ {
286
+ ns: translationKey
287
+ }
288
+ ];
289
+ var FormCellEditor = ({ __gridScope, schema, model, fieldProjection, onSave, onCreate, ...formProps }) => {
290
+ const anchorRef = useRef(null);
291
+ const { id: _gridId, editing: contextEditing, setEditing } = useGridContext2("ArrayEditor", __gridScope);
292
+ const [editing, setLocalEditing] = useState(false);
293
+ useEffect(() => {
294
+ if (contextEditing && contextEditing.cellElement) {
295
+ anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
296
+ setLocalEditing(true);
297
+ } else {
298
+ anchorRef.current = null;
299
+ setLocalEditing(false);
300
+ }
301
+ }, [
302
+ contextEditing
303
+ ]);
304
+ const narrowedSchema = useMemo(() => {
305
+ if (!schema) {
306
+ return void 0;
307
+ }
308
+ return narrowSchema(schema, [
373
309
  fieldProjection.field.path
374
310
  ]);
375
- const originalRow = useMemo3(() => {
376
- if (model && contextEditing) {
377
- const cell = parseCellIndex(contextEditing.index);
311
+ }, [
312
+ JSON.stringify(schema),
313
+ fieldProjection.field.path
314
+ ]);
315
+ const originalRow = useMemo(() => {
316
+ if (model && contextEditing) {
317
+ const cell = parseCellIndex(contextEditing.index);
318
+ if (model.isDraftCell(cell)) {
319
+ const draftRow = model.getDraftRows()[cell.row];
320
+ invariant(draftRow, void 0, {
321
+ F: __dxlog_file,
322
+ L: 74,
323
+ S: void 0,
324
+ A: [
325
+ "draftRow",
326
+ ""
327
+ ]
328
+ });
329
+ return draftRow.data;
330
+ } else {
378
331
  const row = model.getRowAt(cell.row);
379
332
  invariant(row, void 0, {
380
333
  F: __dxlog_file,
381
- L: 55,
334
+ L: 78,
382
335
  S: void 0,
383
336
  A: [
384
337
  "row",
@@ -387,259 +340,222 @@ var FormCellEditor = ({ fieldProjection, model, schema, onSave, __gridScope }) =
387
340
  });
388
341
  return row;
389
342
  }
390
- return void 0;
391
- }, [
392
- model,
393
- contextEditing
394
- ]);
395
- const formValues = useMemo3(() => {
396
- if (originalRow) {
397
- return getSnapshot(originalRow);
398
- }
399
- }, [
400
- originalRow
343
+ }
344
+ return void 0;
345
+ }, [
346
+ model,
347
+ contextEditing
348
+ ]);
349
+ const initialFormValues = useMemo(() => originalRow ? JSON.parse(JSON.stringify(originalRow)) : {}, [
350
+ originalRow
351
+ ]);
352
+ const [formValues, setFormValues] = useState(initialFormValues);
353
+ const handleValuesChanged = useCallback((values) => {
354
+ setFormValues(values);
355
+ }, []);
356
+ const handleOpenChange = useCallback((nextOpen) => {
357
+ if (nextOpen === false) {
358
+ setEditing(null);
359
+ onSave?.();
360
+ }
361
+ setLocalEditing(nextOpen);
362
+ }, []);
363
+ const handleSave = useCallback((values) => {
364
+ if (!originalRow) {
365
+ return;
366
+ }
367
+ const path = fieldProjection.field.path;
368
+ const value = getDeep(values, [
369
+ path
401
370
  ]);
402
- const handleSave = useCallback3((values) => {
403
- const path = fieldProjection.field.path;
404
- const value = getDeep(values, [
405
- path
406
- ]);
371
+ if (model) {
372
+ model.changeRow(originalRow, (mutableRow) => {
373
+ setDeep(mutableRow, [
374
+ path
375
+ ], value);
376
+ });
377
+ } else {
407
378
  setDeep(originalRow, [
408
379
  path
409
380
  ], value);
410
- setEditing(null);
411
- setLocalEditing(false);
412
- onSave?.();
413
- }, [
414
- fieldProjection.field.path,
415
- originalRow
416
- ]);
417
- const handleOpenChange = useCallback3((nextOpen) => {
418
- if (nextOpen === false) {
419
- setEditing(null);
420
- onSave?.();
381
+ }
382
+ contextEditing?.cellElement?.focus();
383
+ setEditing(null);
384
+ setLocalEditing(false);
385
+ onSave?.();
386
+ }, [
387
+ fieldProjection.field.path,
388
+ onSave,
389
+ contextEditing,
390
+ originalRow,
391
+ model
392
+ ]);
393
+ const handleCreate = useCallback((schema2, values) => {
394
+ const objectWithId = onCreate?.(schema2, values);
395
+ if (objectWithId && originalRow) {
396
+ const ref = Ref2.make(objectWithId);
397
+ const path = fieldProjection.field.path;
398
+ if (model) {
399
+ model.changeRow(originalRow, (mutableRow) => {
400
+ setDeep(mutableRow, [
401
+ path
402
+ ], ref);
403
+ });
404
+ } else {
405
+ setDeep(originalRow, [
406
+ path
407
+ ], ref);
421
408
  }
422
- setLocalEditing(nextOpen);
423
- }, []);
424
- if (!editing) {
425
- return null;
426
409
  }
427
- return /* @__PURE__ */ React6.createElement(Popover3.Root, {
428
- open: editing,
429
- onOpenChange: handleOpenChange
430
- }, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
431
- virtualRef: anchorRef
432
- }), /* @__PURE__ */ React6.createElement(Popover3.Content, {
433
- tabIndex: -1,
434
- classNames: "popover-card-width density-fine"
435
- }, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
436
- values: formValues,
437
- schema: narrowedSchema,
438
- onSave: handleSave
439
- }))));
440
- } finally {
441
- _effect.f();
410
+ contextEditing?.cellElement?.focus();
411
+ setEditing(null);
412
+ setLocalEditing(false);
413
+ onSave?.();
414
+ }, [
415
+ fieldProjection.field.path,
416
+ onSave,
417
+ contextEditing,
418
+ originalRow,
419
+ onCreate,
420
+ model
421
+ ]);
422
+ const getOptions = useCallback((results) => results.map((obj) => {
423
+ return {
424
+ id: Entity.getDXN(obj).toString(),
425
+ label: getValue(obj, fieldProjection.field.referencePath) || obj.id.toString()
426
+ };
427
+ }).filter(isTruthy), [
428
+ fieldProjection
429
+ ]);
430
+ if (!editing) {
431
+ return null;
442
432
  }
443
- };
444
-
445
- // src/components/TableCellEditor/extension.ts
446
- import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
447
- import { EditorView } from "@codemirror/view";
448
- var completion = ({ debug, onQuery, onMatch }) => {
449
- return [
450
- EditorView.theme({
451
- ".cm-completionDialog": {
452
- width: "var(--dx-gridCellWidth)"
453
- }
454
- }),
455
- autocompletion({
456
- icons: false,
457
- activateOnTyping: true,
458
- closeOnBlur: !debug,
459
- override: [
460
- async (context) => {
461
- const text = context.state.doc.toString();
462
- return {
463
- from: 0,
464
- options: await onQuery(text)
465
- };
466
- }
467
- ],
468
- // TODO(burdon): Consts from grid (to line-up with grid).
469
- tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
470
- optionClass: () => "flex h-[33px] items-center"
471
- }),
472
- // Check for accepted completion metadata in the transaction.
473
- EditorView.updateListener.of((update) => {
474
- update.transactions.forEach((tr) => {
475
- const completion2 = tr.annotation(pickedCompletion);
476
- if (completion2) {
477
- onMatch(completion2.data);
478
- }
479
- });
480
- })
481
- ];
433
+ return /* @__PURE__ */ React2.createElement(Popover.Root, {
434
+ open: editing,
435
+ onOpenChange: handleOpenChange
436
+ }, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
437
+ virtualRef: anchorRef
438
+ }), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
439
+ tabIndex: -1,
440
+ classNames: "dx-card-popover-width dx-density-fine"
441
+ }, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Root, {
442
+ ...formProps,
443
+ autoFocus: true,
444
+ schema: narrowedSchema,
445
+ values: formValues,
446
+ onValuesChanged: handleValuesChanged,
447
+ projection: model?.projection,
448
+ createInitialValuePath: fieldProjection.field.referencePath,
449
+ createOptionIcon: "ph--plus--regular",
450
+ createOptionLabel,
451
+ db: model?.db,
452
+ getOptions,
453
+ onCreate: handleCreate,
454
+ onSave: handleSave
455
+ }, /* @__PURE__ */ React2.createElement(Form.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Content, null, /* @__PURE__ */ React2.createElement(Form.FieldSet, null), /* @__PURE__ */ React2.createElement(Form.Actions, null))))))));
482
456
  };
483
457
 
484
458
  // src/components/TableCellEditor/TableCellEditor.tsx
485
459
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
486
- var newValue = Symbol.for("newValue");
487
- var createOption = (text) => ({
488
- [newValue]: true,
489
- text
490
- });
491
- var isCreateOption = (data) => typeof data === "object" && data[newValue];
492
- var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onSave, onQuery, __gridScope }) => {
493
- var _effect = _useSignals7();
494
- try {
495
- const { editing } = useGridContext4("TableValueEditor", __gridScope);
496
- const fieldProjection = useMemo4(() => {
497
- if (!model || !editing) {
498
- return;
499
- }
500
- const { col } = parseCellIndex2(editing.index);
501
- const field = model.projection.fields[col];
502
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
503
- invariant2(fieldProjection2, void 0, {
504
- F: __dxlog_file2,
505
- L: 76,
506
- S: void 0,
507
- A: [
508
- "fieldProjection",
509
- ""
510
- ]
511
- });
512
- return fieldProjection2;
513
- }, [
514
- model,
515
- editing
516
- ]);
517
- if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === FormatEnum.SingleSelect) {
518
- return /* @__PURE__ */ React7.createElement(FormCellEditor, {
519
- fieldProjection,
520
- model,
521
- schema,
522
- __gridScope,
523
- onSave
524
- });
460
+ var editorSlots = {
461
+ scroll: {
462
+ className: "!py-(--dx-grid-cell-editor-padding-block)"
463
+ }
464
+ };
465
+ var TableValueEditor = ({ __gridScope, schema, model, modals, onFocus, onSave, onCreate }) => {
466
+ const { editing } = useGridContext3("TableValueEditor", __gridScope);
467
+ const fieldProjection = useMemo2(() => {
468
+ if (!model || !editing) {
469
+ return;
525
470
  }
526
- return /* @__PURE__ */ React7.createElement(TableCellEditor, {
471
+ const { col } = parseCellIndex2(editing.index);
472
+ const field = model.projection.getFields()[col];
473
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
474
+ invariant2(fieldProjection2, void 0, {
475
+ F: __dxlog_file2,
476
+ L: 73,
477
+ S: void 0,
478
+ A: [
479
+ "fieldProjection",
480
+ ""
481
+ ]
482
+ });
483
+ return fieldProjection2;
484
+ }, [
485
+ model,
486
+ editing
487
+ ]);
488
+ if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === Format.TypeFormat.SingleSelect || fieldProjection?.props.format === Format.TypeFormat.Ref) {
489
+ return /* @__PURE__ */ React3.createElement(FormCellEditor, {
490
+ __gridScope,
491
+ schema,
527
492
  model,
493
+ fieldProjection,
528
494
  modals,
529
- onEnter,
530
- onFocus,
531
- onQuery,
532
495
  onSave,
533
- __gridScope
496
+ onCreate
534
497
  });
535
- } finally {
536
- _effect.f();
537
- }
538
- };
539
- var editorSlots = {
540
- scroller: {
541
- className: "!plb-[--dx-grid-cell-editor-padding-block]"
542
498
  }
499
+ return /* @__PURE__ */ React3.createElement(TableCellEditor, {
500
+ model,
501
+ modals,
502
+ onFocus,
503
+ onSave,
504
+ __gridScope
505
+ });
543
506
  };
544
- var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gridScope }) => {
545
- var _effect = _useSignals7();
546
- try {
547
- const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
548
- const suppressNextBlur = useRef2(false);
549
- const { themeMode } = useThemeContext();
550
- const [_validationError, setValidationError] = useState3(null);
551
- const [_validationVariant, setValidationVariant] = useState3("error");
552
- const fieldProjection = useMemo4(() => {
553
- if (!model || !editing) {
554
- return;
555
- }
556
- const { col } = parseCellIndex2(editing.index);
557
- const field = model.projection.fields[col];
558
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
559
- invariant2(fieldProjection2, void 0, {
560
- F: __dxlog_file2,
561
- L: 135,
562
- S: void 0,
563
- A: [
564
- "fieldProjection",
565
- ""
566
- ]
567
- });
568
- return fieldProjection2;
569
- }, [
570
- model,
571
- editing
572
- ]);
573
- useEffect3(() => {
574
- if (!model || !editing || !fieldProjection) {
575
- setValidationError(null);
576
- return;
577
- }
578
- const cell = parseCellIndex2(editing.index);
579
- const { row, col } = cell;
580
- if (model.isDraftCell(cell)) {
581
- const field = model.projection.fields[col];
582
- const hasValidationError = model.hasDraftRowValidationError(row, field.path);
583
- if (hasValidationError) {
584
- const draftRows = model.draftRows.value;
585
- if (row >= 0 && row < draftRows.length) {
586
- const draftRow = draftRows[row];
587
- const validationError = draftRow.validationErrors?.find((error) => error.path === field.path);
588
- if (validationError) {
589
- setValidationError(validationError.message);
590
- setValidationVariant("warning");
591
- }
592
- }
593
- } else {
594
- setValidationError(null);
595
- }
596
- } else {
597
- setValidationError(null);
598
- }
599
- }, [
600
- model,
601
- editing,
602
- fieldProjection
603
- ]);
604
- const handleEnter = useCallback4(async (value) => {
605
- if (!model || !editing) {
606
- return;
607
- }
608
- const cell = parseCellIndex2(editing.index);
609
- const validationResult = await model.validateCellData(cell, value);
610
- if (validationResult.valid) {
611
- setValidationError(null);
612
- model.setCellData(cell, value);
613
- onEnter?.(cell);
614
- onFocus?.();
615
- setEditing(null);
616
- onSave?.();
617
- } else {
618
- setValidationError(validationResult.error);
619
- setValidationVariant("error");
620
- }
621
- }, [
622
- model,
623
- editing,
624
- onEnter,
625
- onFocus,
626
- setEditing
627
- ]);
628
- const handleBlur = useCallback4(async (value) => {
629
- if (!model || !editing) {
630
- return;
631
- }
632
- if (suppressNextBlur.current) {
633
- suppressNextBlur.current = false;
634
- }
635
- }, [
636
- model,
637
- editing
638
- ]);
639
- const handleClose = useCallback4(async (value, event) => {
640
- if (!model || !editing || !fieldProjection) {
641
- return;
642
- }
507
+ var TableCellEditor = ({ __gridScope, model, modals, onFocus, onSave }) => {
508
+ const { editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
509
+ const suppressNextBlur = useRef2(false);
510
+ const [validationError, setValidationError] = useState2(null);
511
+ const [validationVariant, setValidationVariant] = useState2("error");
512
+ const fieldProjection = useMemo2(() => {
513
+ if (!model || !editing) {
514
+ return;
515
+ }
516
+ const { col } = parseCellIndex2(editing.index);
517
+ const field = model.projection.getFields()[col];
518
+ const fieldProjection2 = model.projection.getFieldProjection(field.id);
519
+ invariant2(fieldProjection2, void 0, {
520
+ F: __dxlog_file2,
521
+ L: 120,
522
+ S: void 0,
523
+ A: [
524
+ "fieldProjection",
525
+ ""
526
+ ]
527
+ });
528
+ return fieldProjection2;
529
+ }, [
530
+ model,
531
+ editing
532
+ ]);
533
+ const handleEnter = useCallback2(async (value) => {
534
+ if (!model || !editing) {
535
+ return;
536
+ }
537
+ const cell = parseCellIndex2(editing.index);
538
+ const validationResult = await model.validateCellData(cell, value);
539
+ if (validationResult.valid) {
540
+ setValidationError(null);
541
+ model.setCellData(cell, value);
542
+ onFocus?.();
543
+ setEditing(null);
544
+ onSave?.();
545
+ } else {
546
+ setValidationError(validationResult.error);
547
+ setValidationVariant("error");
548
+ }
549
+ }, [
550
+ model,
551
+ editing,
552
+ onFocus,
553
+ setEditing
554
+ ]);
555
+ const handleBlur = useCallback2(async (value) => {
556
+ if (suppressNextBlur.current) {
557
+ suppressNextBlur.current = false;
558
+ } else if (model && editing) {
643
559
  const cell = parseCellIndex2(editing.index);
644
560
  if (value !== void 0) {
645
561
  const result = await model.validateCellData(cell, value);
@@ -648,171 +564,104 @@ var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, onSave, __gri
648
564
  model.setCellData(cell, value);
649
565
  setEditing(null);
650
566
  onSave?.();
651
- onEnter?.(cell);
652
- if (event && onFocus) {
653
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
654
- }
655
- } else {
656
- setValidationError(result.error);
657
- setValidationVariant("error");
658
567
  }
659
- } else {
568
+ }
569
+ }
570
+ }, [
571
+ model,
572
+ editing
573
+ ]);
574
+ const handleClose = useCallback2(async (value, event) => {
575
+ if (!model || !editing || !fieldProjection) {
576
+ return;
577
+ }
578
+ const cell = parseCellIndex2(editing.index);
579
+ if (value !== void 0) {
580
+ const result = await model.validateCellData(cell, value);
581
+ if (result.valid) {
582
+ suppressNextBlur.current = true;
660
583
  setValidationError(null);
584
+ model.setCellData(cell, value);
661
585
  setEditing(null);
662
586
  onSave?.();
663
587
  if (event && onFocus) {
664
- onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
588
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
665
589
  }
590
+ } else {
591
+ setValidationError(result.error);
592
+ setValidationVariant("error");
666
593
  }
667
- }, [
668
- model,
669
- editing,
670
- onFocus,
671
- onEnter,
672
- fieldProjection,
673
- setEditing,
674
- onSave
675
- ]);
676
- const extension = useMemo4(() => {
677
- if (!fieldProjection) {
678
- return [];
679
- }
680
- const extension2 = [
681
- editorKeys({
682
- onClose: handleClose,
683
- ...editing?.initialContent && {
684
- onNav: handleClose
685
- }
686
- })
687
- ];
688
- const format = fieldProjection.props.format;
689
- if (format === FormatEnum.SingleSelect || format === FormatEnum.MultiSelect) {
690
- extension2.push(createMarkdownExtensions({
691
- themeMode
692
- }));
693
- const options = fieldProjection.props.options || [];
694
- const mode = format === FormatEnum.SingleSelect ? "single-select" : "multi-select";
695
- extension2.push(tagPicker({
696
- mode,
697
- keymap: false,
698
- onSearch: (text, selectedIds) => {
699
- return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
700
- id: option.id,
701
- label: option.title,
702
- hue: option.color
703
- }));
704
- },
705
- onUpdate: (ids) => {
706
- if (model && editing) {
707
- if (ids.length === 0) {
708
- return;
709
- }
710
- if (mode === "single-select") {
711
- void handleEnter(ids[0]);
712
- } else {
713
- void handleEnter(ids);
714
- }
715
- }
716
- }
717
- }));
594
+ } else {
595
+ suppressNextBlur.current = true;
596
+ setValidationError(null);
597
+ setEditing(null);
598
+ onSave?.();
599
+ if (event && onFocus) {
600
+ onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
718
601
  }
719
- if (onQuery) {
720
- switch (fieldProjection.props.format) {
721
- case FormatEnum.Ref: {
722
- extension2.push([
723
- completion({
724
- onQuery: (text) => onQuery(fieldProjection, text),
725
- onMatch: (data) => {
726
- if (model && editing && modals) {
727
- if (isCreateOption(data)) {
728
- const { field, props } = fieldProjection;
729
- if (props.referenceSchema) {
730
- suppressNextBlur.current = true;
731
- modals.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
732
- [field.referencePath]: data.text
733
- }, (data2) => {
734
- void handleEnter(data2);
735
- });
736
- }
737
- } else {
738
- void handleEnter(data);
739
- }
740
- }
741
- }
742
- })
743
- ]);
744
- break;
745
- }
602
+ }
603
+ }, [
604
+ model,
605
+ editing,
606
+ onFocus,
607
+ fieldProjection,
608
+ setEditing,
609
+ onSave
610
+ ]);
611
+ const extensions = useMemo2(() => {
612
+ if (!fieldProjection) {
613
+ return [];
614
+ }
615
+ const extensions2 = [
616
+ editorKeys({
617
+ onClose: handleClose,
618
+ ...editing?.initialContent && {
619
+ onNav: handleClose
746
620
  }
747
- }
748
- return extension2;
749
- }, [
750
- model,
751
- modals,
752
- editing,
753
- fieldProjection,
754
- handleClose,
755
- themeMode
756
- ]);
757
- const getCellContent = useCallback4(() => {
758
- if (model && editing) {
621
+ })
622
+ ];
623
+ if (model && editing) {
624
+ extensions2.push(EditorView.updateListener.of(debounce((update) => {
625
+ const content = update.state.doc.toString();
759
626
  const cell = parseCellIndex2(editing.index);
760
- const { col } = cell;
761
- const field = model.projection.fields[col];
762
- const fieldProjection2 = model.projection.getFieldProjection(field.id);
763
- if (fieldProjection2?.props.format === FormatEnum.SingleSelect || fieldProjection2?.props.format === FormatEnum.MultiSelect) {
764
- const value2 = model.getCellData(cell);
765
- if (value2 !== void 0) {
766
- const options = fieldProjection2.props.options || [];
767
- if (fieldProjection2.props.format === FormatEnum.MultiSelect) {
768
- const tagItems = value2.split(",").map((id) => {
769
- const option = options.find((o) => o.id === id);
770
- if (option) {
771
- return {
772
- id,
773
- label: option.title,
774
- hue: option.color
775
- };
776
- }
777
- return void 0;
778
- }).filter((item) => item !== void 0);
779
- return createLinks(tagItems);
780
- } else {
781
- const option = options.find((o) => o.id === value2);
782
- if (option) {
783
- const tagItem = {
784
- id: value2,
785
- label: option.title,
786
- hue: option.color
787
- };
788
- return createLinks([
789
- tagItem
790
- ]);
791
- }
792
- }
627
+ void model.validateCellData(cell, content).then((result) => {
628
+ if (result.valid) {
629
+ setValidationError(null);
630
+ } else {
631
+ setValidationError(result.error);
632
+ setValidationVariant("error");
793
633
  }
794
- return "";
795
- }
796
- const value = model.getCellData(cell);
797
- return value !== void 0 ? String(value) : "";
798
- }
799
- }, [
800
- model,
801
- editing
802
- ]);
803
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
804
- validationError: _validationError,
805
- variant: _validationVariant,
806
- __gridScope
807
- }), /* @__PURE__ */ React7.createElement(GridCellEditor, {
808
- extension,
809
- getCellContent,
810
- onBlur: handleBlur,
811
- slots: editorSlots
812
- }));
813
- } finally {
814
- _effect.f();
815
- }
634
+ });
635
+ }, 10)));
636
+ }
637
+ return extensions2;
638
+ }, [
639
+ model,
640
+ modals,
641
+ editing,
642
+ fieldProjection,
643
+ handleClose
644
+ ]);
645
+ const getCellContent = useCallback2(() => {
646
+ if (model && editing) {
647
+ const cell = parseCellIndex2(editing.index);
648
+ const value = model.getCellData(cell);
649
+ return value !== void 0 ? String(value) : "";
650
+ }
651
+ }, [
652
+ model,
653
+ editing
654
+ ]);
655
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
656
+ validationError,
657
+ variant: validationVariant,
658
+ __gridScope
659
+ }), /* @__PURE__ */ React3.createElement(GridCellEditor, {
660
+ extensions,
661
+ getCellContent,
662
+ onBlur: handleBlur,
663
+ slots: editorSlots
664
+ }));
816
665
  };
817
666
  var determineNavigationAxis = ({ key }) => {
818
667
  switch (key) {
@@ -839,491 +688,688 @@ var determineNavigationDelta = ({ key, shift }) => {
839
688
  return shift ? -1 : 1;
840
689
  };
841
690
 
691
+ // src/components/TableToolbar/TableToolbar.tsx
692
+ import { Atom as Atom2, RegistryContext } from "@effect-atom/atom-react";
693
+ import React4, { useContext, useEffect as useEffect2, useMemo as useMemo3 } from "react";
694
+ import { Menu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
695
+ var createTableToolbarActions = ({ stateAtom, onAdd, onSave, customActions }) => Atom2.make((get) => {
696
+ const nodes = [];
697
+ if (onAdd) {
698
+ const add = createMenuAction("add-row", onAdd, {
699
+ type: "add-row",
700
+ icon: "ph--plus--regular",
701
+ label: [
702
+ "add row label",
703
+ {
704
+ ns: translationKey
705
+ }
706
+ ],
707
+ testId: "table.toolbar.add-row"
708
+ });
709
+ nodes.push(add);
710
+ }
711
+ if (onSave) {
712
+ const state = get(stateAtom);
713
+ const save = createMenuAction("save-view", onSave, {
714
+ type: "save-view",
715
+ icon: "ph--floppy-disk--regular",
716
+ label: [
717
+ "save view label",
718
+ {
719
+ ns: translationKey
720
+ }
721
+ ],
722
+ testId: "table.toolbar.save-view",
723
+ iconOnly: false,
724
+ hidden: !state.viewDirty
725
+ });
726
+ nodes.push(save);
727
+ }
728
+ const gap = createGapSeparator();
729
+ nodes.push(...gap.nodes);
730
+ const edges = nodes.map(({ id: target }) => ({
731
+ source: "root",
732
+ target,
733
+ relation: "child"
734
+ }));
735
+ if (customActions) {
736
+ const custom = get(customActions);
737
+ nodes.push(...custom.nodes);
738
+ edges.push(...custom.edges);
739
+ }
740
+ return {
741
+ nodes,
742
+ edges
743
+ };
744
+ });
745
+ var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions, ...props }) => {
746
+ const registry = useContext(RegistryContext);
747
+ const stateAtom = useMemo3(() => Atom2.make({
748
+ viewDirty
749
+ }), []);
750
+ useEffect2(() => {
751
+ registry.set(stateAtom, {
752
+ viewDirty
753
+ });
754
+ }, [
755
+ registry,
756
+ stateAtom,
757
+ viewDirty
758
+ ]);
759
+ const actionsCreator = useMemo3(() => createTableToolbarActions({
760
+ stateAtom,
761
+ onAdd,
762
+ onSave,
763
+ customActions
764
+ }), [
765
+ stateAtom,
766
+ onAdd,
767
+ onSave,
768
+ customActions
769
+ ]);
770
+ const menu = useMenuActions(actionsCreator);
771
+ return /* @__PURE__ */ React4.createElement(Menu.Root, {
772
+ ...menu,
773
+ attendableId
774
+ }, /* @__PURE__ */ React4.createElement(Menu.Toolbar, {
775
+ ...props,
776
+ classNames
777
+ }));
778
+ };
779
+
780
+ // src/components/Table/ColumnActionsMenu.tsx
781
+ import { useAtomValue } from "@effect-atom/atom-react";
782
+ import React5 from "react";
783
+ import { DropdownMenu, useTranslation } from "@dxos/react-ui";
784
+ var ColumnActionsMenu = ({ model, modals }) => {
785
+ const { t } = useTranslation(translationKey);
786
+ const state = useAtomValue(modals.state);
787
+ if (state?.type !== "column") {
788
+ return null;
789
+ }
790
+ const currentSort = model.getSorting();
791
+ const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
792
+ return /* @__PURE__ */ React5.createElement(DropdownMenu.Root, {
793
+ modal: false,
794
+ open: true,
795
+ onOpenChange: modals.close
796
+ }, /* @__PURE__ */ React5.createElement(DropdownMenu.VirtualTrigger, {
797
+ virtualRef: modals.trigger
798
+ }), /* @__PURE__ */ React5.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React5.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React5.createElement(DropdownMenu.Item, {
799
+ "data-testid": "column-sort-descending",
800
+ onClick: () => model.setSort(state.fieldId, "desc")
801
+ }, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React5.createElement(DropdownMenu.Item, {
802
+ "data-testid": "column-sort-ascending",
803
+ onClick: () => model.setSort(state.fieldId, "asc")
804
+ }, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React5.createElement(DropdownMenu.Item, {
805
+ "data-testid": "column-clear-sort",
806
+ onClick: () => model.clearSort()
807
+ }, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React5.createElement(DropdownMenu.Item, {
808
+ "data-testid": "column-delete",
809
+ onClick: () => model.deleteColumn(state.fieldId)
810
+ }, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React5.createElement(DropdownMenu.Item, {
811
+ "data-testid": "column-settings",
812
+ onClick: () => modals.openColumnSettings()
813
+ }, t("column action settings"))), /* @__PURE__ */ React5.createElement(DropdownMenu.Arrow, null))));
814
+ };
815
+
816
+ // src/components/Table/ColumnSettings.tsx
817
+ import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
818
+ import React6, { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo4, useState as useState3 } from "react";
819
+ import { Popover as Popover2 } from "@dxos/react-ui";
820
+ import { FieldEditor } from "@dxos/react-ui-form";
821
+ var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
822
+ const [newField, setNewField] = useState3();
823
+ const state = useAtomValue2(modals.state);
824
+ useEffect3(() => {
825
+ if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
826
+ setNewField(model.projection.createFieldProjection());
827
+ requestAnimationFrame(() => {
828
+ onNewColumn();
829
+ });
830
+ } else {
831
+ setNewField(void 0);
832
+ }
833
+ }, [
834
+ model?.projection,
835
+ state
836
+ ]);
837
+ const existingField = useMemo4(() => {
838
+ if (state?.type === "columnSettings") {
839
+ const { mode } = state;
840
+ if (mode.type === "edit") {
841
+ return model?.projection?.getFields().find((f) => f.id === mode.fieldId);
842
+ }
843
+ }
844
+ return void 0;
845
+ }, [
846
+ model?.projection,
847
+ state
848
+ ]);
849
+ const field = existingField ?? newField;
850
+ const handleSave = useCallback3(() => {
851
+ modals.close();
852
+ }, [
853
+ modals
854
+ ]);
855
+ const handleCancel = useCallback3(() => {
856
+ if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
857
+ model?.projection.deleteFieldProjection(newField.id);
858
+ }
859
+ }, [
860
+ model?.projection,
861
+ state,
862
+ newField
863
+ ]);
864
+ if (!model?.projection || !field) {
865
+ return null;
866
+ }
867
+ return /* @__PURE__ */ React6.createElement(Popover2.Root, {
868
+ modal: false,
869
+ open: state?.type === "columnSettings"
870
+ }, /* @__PURE__ */ React6.createElement(Popover2.VirtualTrigger, {
871
+ virtualRef: modals.trigger
872
+ }), /* @__PURE__ */ React6.createElement(Popover2.Portal, null, /* @__PURE__ */ React6.createElement(Popover2.Content, {
873
+ classNames: "md:w-64"
874
+ }, /* @__PURE__ */ React6.createElement(Popover2.Viewport, null, /* @__PURE__ */ React6.createElement(FieldEditor, {
875
+ projection: model.projection,
876
+ field,
877
+ registry,
878
+ onSave: handleSave,
879
+ onCancel: handleCancel
880
+ })), /* @__PURE__ */ React6.createElement(Popover2.Arrow, null))));
881
+ };
882
+
883
+ // src/components/Table/RowActionsMenu.tsx
884
+ import { useAtomValue as useAtomValue3 } from "@effect-atom/atom-react";
885
+ import React7 from "react";
886
+ import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
887
+ var RowActionsMenu = ({ model, modals }) => {
888
+ const { t } = useTranslation2(translationKey);
889
+ const hasSelection = model.selection.hasSelection;
890
+ const state = useAtomValue3(modals.state);
891
+ if (state?.type !== "row") {
892
+ return null;
893
+ }
894
+ return /* @__PURE__ */ React7.createElement(DropdownMenu2.Root, {
895
+ modal: false,
896
+ open: true,
897
+ onOpenChange: modals.close
898
+ }, /* @__PURE__ */ React7.createElement(DropdownMenu2.VirtualTrigger, {
899
+ virtualRef: modals.trigger
900
+ }), /* @__PURE__ */ React7.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React7.createElement(DropdownMenu2.Viewport, null, model.rowActions?.length > 0 && /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(DropdownMenu2.Group, null, model.rowActions?.map((action) => /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
901
+ key: action.id,
902
+ "data-testid": `row-action-${action.id}`,
903
+ onClick: () => {
904
+ modals.close();
905
+ model.handleRowAction(action.id, state.rowIndex);
906
+ }
907
+ }, toLocalizedString(action.label, t)))), /* @__PURE__ */ React7.createElement(DropdownMenu2.Separator, null)), model.features.dataEditable !== false && /* @__PURE__ */ React7.createElement(DropdownMenu2.Item, {
908
+ "data-testid": "row-menu-delete",
909
+ onClick: () => model.deleteRow(state.rowIndex)
910
+ }, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React7.createElement(DropdownMenu2.Arrow, null)));
911
+ };
912
+
842
913
  // src/components/Table/Table.tsx
843
914
  var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
844
- var TableRoot = ({ children, role = "article" }) => {
845
- var _effect = _useSignals8();
846
- try {
847
- return /* @__PURE__ */ React8.createElement("div", {
848
- role: "none",
849
- className: mx("relative !border-separator [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]", role === "card--popover" && "popover-card-height", role === "section" && "attention-surface", role === "card--intrinsic" && "[&_.dx-grid]:bs-[--dx-grid-content-block-size]", [
850
- "card--popover",
851
- "section",
852
- "card--extrinsic"
853
- ].includes(role) && "overflow-hidden", [
854
- "article",
855
- "slide"
856
- ].includes(role) && "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:bs-0")
857
- }, children);
858
- } finally {
859
- _effect.f();
915
+ var columnDefault = {
916
+ grid: {
917
+ minSize: 80,
918
+ maxSize: 640
860
919
  }
861
920
  };
862
- var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention, schema, client, onRowClick }, forwardedRef) => {
863
- var _effect = _useSignals8();
864
- try {
865
- const [dxGrid, setDxGrid] = useState4(null);
866
- const { hasAttention } = useAttention(model?.id ?? "table");
867
- const { t } = useTranslation3(translationKey);
868
- const modals = useMemo5(() => new ModalController(), []);
869
- const draftRowCount = model?.getDraftRowCount() ?? 0;
870
- const frozen = useMemo5(() => {
871
- const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
872
- return {
873
- frozenRowsStart: 1,
874
- frozenRowsEnd: draftRowCount,
875
- frozenColsStart: model?.features.selection.enabled ? 1 : 0,
876
- frozenColsEnd: noActionColumn ? 0 : 1
877
- };
878
- }, [
879
- model,
880
- draftRowCount
881
- ]);
882
- const getCells = useCallback5((range, plane) => presentation?.getCells(range, plane) ?? {}, [
883
- presentation
884
- ]);
885
- useEffect4(() => {
886
- if (!presentation || !dxGrid) {
887
- return;
888
- }
889
- dxGrid.getCells = getCells;
890
- }, [
891
- presentation,
892
- dxGrid,
893
- getCells
894
- ]);
895
- useImperativeHandle(forwardedRef, () => {
896
- if (!presentation || !dxGrid) {
897
- return {};
921
+ var rowDefault = {
922
+ frozenRowsStart: {
923
+ readonly: true,
924
+ focusUnfurl: false
925
+ }
926
+ };
927
+ var emptyColumnMeta = Atom3.make({
928
+ grid: {}
929
+ });
930
+ var TableRoot = ({ children }) => {
931
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, null, children);
932
+ };
933
+ var emptyRowsAtom = Atom3.make([]);
934
+ var emptyCellUpdateAtom = Atom3.make(0);
935
+ var TableMainInner = ({ schema, model, presentation, ignoreAttention, onCreate, onRowClick, testId, ...props }, forwardedRef) => {
936
+ const registry = useContext2(RegistryContext2);
937
+ const [dxGrid, setDxGrid] = useState4(null);
938
+ const { hasAttention } = useAttention(model?.id ?? "table");
939
+ const modals = useMemo5(() => new ModalController(registry), [
940
+ registry
941
+ ]);
942
+ const columnMeta = useAtomValue4(model?.columnMeta ?? emptyColumnMeta);
943
+ const rows = useAtomValue4(model?.rows ?? emptyRowsAtom);
944
+ const cellUpdateCounter = useAtomValue4(model?.cellUpdate ?? emptyCellUpdateAtom);
945
+ const columnCount = Object.keys(columnMeta.grid).length || model?.projection.getFields().length || 0;
946
+ const draftRowCount = model?.getDraftRowCount() ?? 0;
947
+ const frozen = useMemo5(() => {
948
+ const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
949
+ return {
950
+ frozenRowsStart: 1,
951
+ frozenRowsEnd: Math.max(1, draftRowCount),
952
+ frozenColsStart: model?.features.selection.enabled ? 1 : 0,
953
+ frozenColsEnd: noActionColumn ? 0 : 1
954
+ };
955
+ }, [
956
+ model,
957
+ draftRowCount
958
+ ]);
959
+ const getCells = useCallback4((range, plane) => presentation?.getCells(range, plane) ?? {}, [
960
+ presentation
961
+ ]);
962
+ useEffect4(() => {
963
+ if (!dxGrid || !presentation) {
964
+ return;
965
+ }
966
+ dxGrid.getCells = getCells;
967
+ }, [
968
+ dxGrid,
969
+ presentation,
970
+ getCells
971
+ ]);
972
+ useEffect4(() => {
973
+ if (!dxGrid) {
974
+ return;
975
+ }
976
+ dxGrid.updateCells(true);
977
+ dxGrid.requestUpdate();
978
+ }, [
979
+ dxGrid,
980
+ rows,
981
+ cellUpdateCounter
982
+ ]);
983
+ const handleInsertRowResult = useCallback4((insertResult) => {
984
+ if (insertResult === "draft") {
985
+ requestAnimationFrame(() => {
986
+ dxGrid?.setFocus({
987
+ plane: "frozenRowsEnd",
988
+ col: 0,
989
+ row: 0
990
+ });
991
+ dxGrid?.refocus();
992
+ });
993
+ } else {
994
+ requestAnimationFrame(() => {
995
+ dxGrid?.setFocus({
996
+ plane: "grid",
997
+ col: 0,
998
+ row: model ? model.getRowCount() - 1 : 0
999
+ });
1000
+ dxGrid?.refocus();
1001
+ });
1002
+ }
1003
+ }, [
1004
+ model,
1005
+ dxGrid
1006
+ ]);
1007
+ const handleSave = useCallback4(() => {
1008
+ dxGrid?.updateCells(true);
1009
+ dxGrid?.requestUpdate();
1010
+ }, [
1011
+ dxGrid
1012
+ ]);
1013
+ const handleSaveDraftRow = useCallback4((rowIndex = 0) => {
1014
+ if (model && dxGrid) {
1015
+ const didCommitSuccessfully = model.commitDraftRow(rowIndex);
1016
+ if (didCommitSuccessfully) {
1017
+ requestAnimationFrame(() => {
1018
+ dxGrid.scrollToEndRow();
1019
+ });
898
1020
  }
899
- return {
900
- update: (cell) => {
901
- if (cell) {
902
- dxGrid.updateIfWithinBounds(cell, true);
903
- } else {
904
- dxGrid.updateCells(true);
905
- dxGrid.requestUpdate();
906
- }
907
- }
908
- };
909
- }, [
910
- presentation,
911
- dxGrid
912
- ]);
913
- const handleGridClick = useCallback5((event) => {
914
- const rowIndex = safeParseInt(event.target.closest("[aria-rowindex]")?.ariaRowIndex ?? "");
915
- if (rowIndex != null) {
916
- if (onRowClick) {
1021
+ }
1022
+ }, [
1023
+ model,
1024
+ dxGrid
1025
+ ]);
1026
+ const handleGridClick = useCallback4((event) => {
1027
+ const cell = closestCell(event.target);
1028
+ if (cell) {
1029
+ const { row: rowIndex, plane } = cell;
1030
+ if (onRowClick) {
1031
+ if (plane === "grid") {
917
1032
  const row = model?.getRowAt(rowIndex);
918
1033
  row && onRowClick(row);
1034
+ } else {
1035
+ onRowClick(cell);
919
1036
  }
920
- if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
921
- model.selection.toggleSelectionForRowIndex(rowIndex);
922
- }
923
1037
  }
924
- if (!modals) {
1038
+ if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
1039
+ model.selection.toggleSelectionForRowIndex(rowIndex);
1040
+ }
1041
+ }
1042
+ if (!modals) {
1043
+ return;
1044
+ }
1045
+ const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
1046
+ const tableButtonElement = event.target.closest(buttonSelector);
1047
+ if (tableButtonElement) {
1048
+ const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
1049
+ if (!button) {
925
1050
  return;
926
1051
  }
927
- const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
928
- const tableButtonElement = event.target.closest(buttonSelector);
929
- if (tableButtonElement) {
930
- const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
931
- if (!button) {
932
- return;
1052
+ modals.setTrigger(tableButtonElement);
1053
+ const data = button.getData(tableButtonElement);
1054
+ switch (data.type) {
1055
+ case "rowMenu": {
1056
+ modals.showRowMenu(data.rowIndex);
1057
+ break;
933
1058
  }
934
- modals.setTrigger(tableButtonElement);
935
- const data = button.getData(tableButtonElement);
936
- switch (data.type) {
937
- case "rowMenu": {
938
- modals.showRowMenu(data.rowIndex);
939
- break;
940
- }
941
- case "columnSettings": {
942
- modals.showColumnMenu(data.fieldId);
943
- break;
944
- }
945
- case "newColumn": {
946
- modals.showColumnCreator();
947
- break;
948
- }
949
- case "sort": {
950
- model?.sorting?.toggleSort(data.fieldId);
951
- break;
952
- }
953
- case "saveDraftRow": {
954
- if (model) {
955
- const didCommitSuccessfully = model.commitDraftRow(data.rowIndex);
956
- if (dxGrid && didCommitSuccessfully) {
957
- requestAnimationFrame(() => {
958
- dxGrid.scrollToEndRow();
959
- });
960
- }
961
- }
962
- break;
963
- }
1059
+ case "columnSettings": {
1060
+ modals.showColumnMenu(data.fieldId);
1061
+ break;
964
1062
  }
965
- return;
966
- }
967
- const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
968
- const controlElement = event.target.closest(controlSelector);
969
- if (controlElement) {
970
- const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
971
- if (!control) {
972
- return;
1063
+ case "newColumn": {
1064
+ modals.showColumnCreator();
1065
+ break;
973
1066
  }
974
- const data = control.getData(controlElement);
975
- switch (data.type) {
976
- case "checkbox": {
977
- if (data.header) {
978
- model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
979
- } else {
980
- model?.selection.toggleSelectionForRowIndex(data.rowIndex);
981
- }
982
- break;
983
- }
984
- case "switch": {
985
- if (model) {
986
- model.updateCellData({
987
- row: data.rowIndex,
988
- col: data.colIndex
989
- }, (value) => !value);
990
- }
991
- break;
992
- }
1067
+ case "sort": {
1068
+ model?.toggleSort(data.fieldId);
1069
+ break;
993
1070
  }
994
- }
995
- }, [
996
- model,
997
- modals,
998
- dxGrid
999
- ]);
1000
- const handleFocus = useCallback5((increment, delta) => {
1001
- if (dxGrid) {
1002
- dxGrid.refocus(increment, delta);
1003
- }
1004
- }, [
1005
- dxGrid
1006
- ]);
1007
- const handleEnter = useCallback5((cell) => {
1008
- if (!model?.features.dataEditable) {
1009
- return;
1010
- }
1011
- if (model && cell.row === model.getRowCount() - 1) {
1012
- model.insertRow();
1013
- if (dxGrid) {
1014
- requestAnimationFrame(() => {
1015
- dxGrid?.scrollToRow(cell.row + 1);
1016
- dxGrid?.refocus("row", 1);
1017
- });
1071
+ case "saveDraftRow": {
1072
+ handleSaveDraftRow();
1073
+ break;
1018
1074
  }
1019
1075
  }
1020
- }, [
1021
- model,
1022
- dxGrid
1023
- ]);
1024
- const handleKeyDown = useCallback5((event) => {
1025
- if (!model?.features.dataEditable) {
1026
- return;
1027
- }
1028
- const cell = closestCell(event.target);
1029
- if (!model || !cell) {
1076
+ return;
1077
+ }
1078
+ const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
1079
+ const controlElement = event.target.closest(controlSelector);
1080
+ if (controlElement) {
1081
+ const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
1082
+ if (!control) {
1030
1083
  return;
1031
1084
  }
1032
- switch (event.key) {
1033
- case "Backspace":
1034
- case "Delete": {
1035
- model.setCellData(cell, void 0);
1085
+ const data = control.getData(controlElement);
1086
+ switch (data.type) {
1087
+ case "checkbox": {
1088
+ if (data.header) {
1089
+ model?.selection.setSelection(model.selection.allRowsSelected ? "none" : "all");
1090
+ } else {
1091
+ model?.selection.toggleSelectionForRowIndex(data.rowIndex);
1092
+ }
1093
+ break;
1094
+ }
1095
+ case "switch": {
1096
+ if (model) {
1097
+ model.updateCellData({
1098
+ row: data.rowIndex,
1099
+ col: data.colIndex
1100
+ }, (value) => !value);
1101
+ }
1036
1102
  break;
1037
1103
  }
1038
1104
  }
1039
- }, [
1040
- model
1041
- ]);
1042
- const handleAxisResize = useCallback5((event) => {
1043
- if (event.axis === "col") {
1044
- const columnIndex = parseInt(event.index, 10);
1045
- model?.setColumnWidth(columnIndex, event.size);
1046
- }
1047
- }, [
1048
- model
1049
- ]);
1050
- const handleWheel = useCallback5((event) => {
1051
- if (!ignoreAttention && !hasAttention) {
1052
- event.stopPropagation();
1053
- }
1054
- }, [
1055
- hasAttention,
1056
- ignoreAttention
1057
- ]);
1058
- const handleNewColumn = useCallback5(() => {
1059
- const columns = model?.getColumnCount();
1060
- if (dxGrid && columns) {
1061
- dxGrid.scrollToColumn(columns - 1);
1105
+ }
1106
+ }, [
1107
+ model,
1108
+ modals,
1109
+ dxGrid
1110
+ ]);
1111
+ const handleFocus = useCallback4((increment, delta, cell) => {
1112
+ if (dxGrid && model) {
1113
+ if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1 && increment !== "col") {
1114
+ handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : "final");
1115
+ } else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
1116
+ handleSaveDraftRow(cell.row);
1117
+ handleInsertRowResult(model.insertRow());
1118
+ } else {
1119
+ dxGrid.refocus(increment, delta);
1062
1120
  }
1063
- }, [
1064
- model,
1065
- dxGrid
1066
- ]);
1067
- const handleQuery = useCallback5(async ({ field, props }, text) => {
1068
- if (model && props.referenceSchema && field.referencePath) {
1069
- const space = getSpace2(model.view);
1070
- invariant3(space, void 0, {
1071
- F: __dxlog_file3,
1072
- L: 325,
1073
- S: void 0,
1074
- A: [
1075
- "space",
1076
- ""
1077
- ]
1078
- });
1079
- let schema2;
1080
- if (client) {
1081
- schema2 = client.graph.schemaRegistry.getSchema(props.referenceSchema);
1082
- }
1083
- if (!schema2) {
1084
- schema2 = space.db.schemaRegistry.getSchema(props.referenceSchema);
1121
+ }
1122
+ }, [
1123
+ dxGrid,
1124
+ model
1125
+ ]);
1126
+ const handleKeyDown = useCallback4((event) => {
1127
+ if (!model?.features.dataEditable) {
1128
+ return;
1129
+ }
1130
+ const cell = closestCell(event.target);
1131
+ if (!model || !cell) {
1132
+ return;
1133
+ }
1134
+ if (event.metaKey || event.ctrlKey) {
1135
+ switch (event.key) {
1136
+ case "c": {
1137
+ try {
1138
+ const cellData = model.getCellData(cell);
1139
+ const textContent = cellData?.toString() ?? "";
1140
+ void navigator.clipboard.writeText(textContent);
1141
+ event.preventDefault();
1142
+ } catch (error) {
1143
+ log.catch(error, void 0, {
1144
+ F: __dxlog_file3,
1145
+ L: 310,
1146
+ S: void 0,
1147
+ C: (f, a) => f(...a)
1148
+ });
1149
+ }
1150
+ break;
1085
1151
  }
1086
- if (schema2) {
1087
- const { objects } = await space.db.query(Filter.type(schema2)).run();
1088
- const options = objects.map((obj) => {
1089
- const value = getValue(obj, field.referencePath);
1090
- if (!value || typeof value !== "string") {
1091
- return void 0;
1092
- }
1093
- return {
1094
- label: value,
1095
- data: obj
1096
- };
1097
- }).filter(isNotFalsy);
1098
- return [
1099
- ...options,
1100
- {
1101
- label: t("create new object label", {
1102
- text
1103
- }),
1104
- data: createOption(text)
1152
+ case "v": {
1153
+ event.preventDefault();
1154
+ void navigator.clipboard.readText().then((clipboardText) => {
1155
+ try {
1156
+ model.setCellData(cell, String2.trim(clipboardText).replace(/[\n\r]+/, " "));
1157
+ handleSave();
1158
+ } catch {
1159
+ const cellElement = event.target.closest('[data-dx-grid-action="cell"]');
1160
+ if (cellElement) {
1161
+ const rect = cellElement.getBoundingClientRect();
1162
+ const editRequest = new DxEditRequest({
1163
+ cellIndex: `${cell.plane},${cell.col},${cell.row}`,
1164
+ cellBox: {
1165
+ insetInlineStart: rect.left,
1166
+ insetBlockStart: rect.top,
1167
+ inlineSize: rect.width,
1168
+ blockSize: rect.height
1169
+ },
1170
+ cellElement,
1171
+ initialContent: clipboardText
1172
+ });
1173
+ cellElement.dispatchEvent(editRequest);
1174
+ }
1105
1175
  }
1106
- ];
1176
+ });
1177
+ break;
1107
1178
  }
1108
1179
  }
1109
- return [];
1110
- }, [
1111
- model,
1112
- client,
1113
- t
1114
- ]);
1115
- const handleSave = useCallback5(() => {
1116
- dxGrid?.updateCells(true);
1117
- }, [
1118
- dxGrid
1119
- ]);
1120
- if (!model || !modals) {
1121
- return /* @__PURE__ */ React8.createElement("span", {
1122
- role: "none",
1123
- className: "attention-surface"
1124
- });
1125
1180
  }
1126
- return /* @__PURE__ */ React8.createElement(Grid.Root, {
1127
- id: model.id ?? "table-grid"
1128
- }, /* @__PURE__ */ React8.createElement(TableValueEditor, {
1129
- model,
1130
- modals,
1131
- schema,
1132
- onEnter: handleEnter,
1133
- onFocus: handleFocus,
1134
- onQuery: handleQuery,
1135
- onSave: handleSave
1136
- }), /* @__PURE__ */ React8.createElement(Grid.Content, {
1137
- className: mx("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1138
- frozen,
1139
- columns: model.columnMeta.value,
1140
- limitRows: model.getRowCount() ?? 0,
1141
- limitColumns: model.projection.fields.length,
1142
- overscroll: "trap",
1143
- onAxisResize: handleAxisResize,
1144
- onClick: handleGridClick,
1145
- onKeyDown: handleKeyDown,
1146
- onWheelCapture: handleWheel,
1147
- ref: setDxGrid
1148
- }), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
1149
- model,
1150
- modals
1151
- }), /* @__PURE__ */ React8.createElement(ColumnActionsMenu, {
1152
- model,
1153
- modals
1154
- }), /* @__PURE__ */ React8.createElement(ColumnSettings, {
1155
- model,
1156
- modals,
1157
- onNewColumn: handleNewColumn
1158
- }), /* @__PURE__ */ React8.createElement(CreateRefPanel, {
1159
- model,
1160
- modals
1161
- }));
1162
- } finally {
1163
- _effect.f();
1181
+ switch (event.key) {
1182
+ case "Backspace":
1183
+ case "Delete": {
1184
+ try {
1185
+ model.setCellData(cell, void 0);
1186
+ event.preventDefault();
1187
+ handleSave();
1188
+ } catch {
1189
+ }
1190
+ break;
1191
+ }
1192
+ }
1193
+ }, [
1194
+ model,
1195
+ dxGrid,
1196
+ handleSave
1197
+ ]);
1198
+ const handleAxisResize = useCallback4((event) => {
1199
+ if (event.axis === "col") {
1200
+ const columnIndex = parseInt(event.index, 10);
1201
+ model?.setColumnWidth(columnIndex, event.size);
1202
+ }
1203
+ }, [
1204
+ model
1205
+ ]);
1206
+ const handleWheel = useCallback4((event) => {
1207
+ if (!ignoreAttention && !hasAttention) {
1208
+ event.stopPropagation();
1209
+ }
1210
+ }, [
1211
+ hasAttention,
1212
+ ignoreAttention
1213
+ ]);
1214
+ const handleNewColumn = useCallback4(() => {
1215
+ const columns = model?.getColumnCount();
1216
+ if (dxGrid && columns) {
1217
+ dxGrid.scrollToColumn(columns - 1);
1218
+ }
1219
+ }, [
1220
+ model,
1221
+ dxGrid
1222
+ ]);
1223
+ useImperativeHandle(forwardedRef, () => {
1224
+ if (!dxGrid || !presentation) {
1225
+ return {};
1226
+ }
1227
+ return {
1228
+ update: (cell) => {
1229
+ if (cell) {
1230
+ dxGrid.updateIfWithinBounds(cell, true);
1231
+ } else {
1232
+ dxGrid.updateCells(true);
1233
+ dxGrid.requestUpdate();
1234
+ }
1235
+ },
1236
+ handleInsertRowResult
1237
+ };
1238
+ }, [
1239
+ dxGrid,
1240
+ model,
1241
+ presentation
1242
+ ]);
1243
+ if (!model || !modals) {
1244
+ return /* @__PURE__ */ React8.createElement("span", {
1245
+ role: "none",
1246
+ className: "dx-attention-surface"
1247
+ });
1164
1248
  }
1165
- });
1249
+ const { className, ...rest } = useComposableProps(props);
1250
+ return /* @__PURE__ */ React8.createElement("div", {
1251
+ ...rest,
1252
+ role: "none",
1253
+ className: mx("dx-container relative", className)
1254
+ }, /* @__PURE__ */ React8.createElement(Grid.Root, {
1255
+ id: model.id ?? "table-grid"
1256
+ }, /* @__PURE__ */ React8.createElement(TableValueEditor, {
1257
+ model,
1258
+ modals,
1259
+ schema,
1260
+ onFocus: handleFocus,
1261
+ onSave: handleSave,
1262
+ onCreate
1263
+ }), /* @__PURE__ */ React8.createElement(Grid.Content, {
1264
+ className: mx("[--dx-grid-base:var(--base-surface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
1265
+ frozen,
1266
+ columns: columnMeta,
1267
+ columnDefault,
1268
+ rowDefault,
1269
+ limitRows: rows.length,
1270
+ limitColumns: columnCount,
1271
+ overscroll: "trap",
1272
+ onAxisResize: handleAxisResize,
1273
+ onClick: handleGridClick,
1274
+ onKeyDownCapture: handleKeyDown,
1275
+ onWheelCapture: handleWheel,
1276
+ ...testId && {
1277
+ "data-testid": testId
1278
+ },
1279
+ ref: setDxGrid
1280
+ }), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
1281
+ model,
1282
+ modals
1283
+ }), /* @__PURE__ */ React8.createElement(ColumnActionsMenu, {
1284
+ model,
1285
+ modals
1286
+ }), /* @__PURE__ */ React8.createElement(ColumnSettings, {
1287
+ model,
1288
+ modals,
1289
+ onNewColumn: handleNewColumn
1290
+ })));
1291
+ };
1292
+ var TableMain = /* @__PURE__ */ forwardRef(TableMainInner);
1166
1293
  var Table = {
1167
1294
  Root: TableRoot,
1168
- Main: TableMain
1295
+ Main: TableMain,
1296
+ Toolbar: TableToolbar
1169
1297
  };
1170
1298
 
1171
1299
  // src/components/Table/DynamicTable.tsx
1172
- import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
1173
- import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
1300
+ import { RegistryContext as RegistryContext3 } from "@effect-atom/atom-react";
1301
+ import React9, { useCallback as useCallback5, useContext as useContext3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef3, useState as useState5 } from "react";
1174
1302
  import { useDefaultValue } from "@dxos/react-ui";
1175
- import { mx as mx2 } from "@dxos/react-ui-theme";
1176
- var DynamicTable = ({ classNames, name = "example.com/dynamic-table", rows, properties, jsonSchema: _jsonSchema, schema, rowActions, onRowClick, onRowAction, ...props }) => {
1177
- var _effect = _useSignals9();
1178
- try {
1179
- const { typename, jsonSchema } = useMemo6(() => getBaseSchema({
1180
- typename: name,
1181
- properties,
1182
- jsonSchema: _jsonSchema,
1183
- schema
1184
- }), [
1185
- name,
1186
- properties,
1187
- _jsonSchema,
1188
- schema
1189
- ]);
1190
- const { projection, view } = useMemo6(() => makeDynamicTable({
1191
- typename,
1192
- jsonSchema,
1193
- properties
1194
- }), [
1195
- typename,
1303
+ import { mx as mx2 } from "@dxos/ui-theme";
1304
+ var DynamicTable = ({ classNames, schema, name = "example.com/dynamic-table", rows, properties, jsonSchema: jsonSchemaProp, rowActions, onRowClick, onRowAction, ...props }) => {
1305
+ const registry = useContext3(RegistryContext3);
1306
+ const [dynamicTable, setDynamicTable] = useState5();
1307
+ const { jsonSchema } = useMemo6(() => getBaseSchema({
1308
+ typename: name,
1309
+ properties,
1310
+ jsonSchema: jsonSchemaProp,
1311
+ schema
1312
+ }), [
1313
+ name,
1314
+ properties,
1315
+ jsonSchemaProp,
1316
+ schema
1317
+ ]);
1318
+ useEffect5(() => {
1319
+ setDynamicTable(makeDynamicTable({
1320
+ registry,
1196
1321
  jsonSchema,
1197
1322
  properties
1198
- ]);
1199
- const tableRef = useRef3(null);
1200
- const handleCellUpdate = useCallback6((cell) => {
1201
- tableRef.current?.update?.(cell);
1202
- }, []);
1203
- const handleRowOrderChange = useCallback6(() => {
1204
- tableRef.current?.update?.();
1205
- }, []);
1206
- const features = useDefaultValue(props.features, () => ({
1207
- selection: {
1208
- enabled: false
1209
- },
1210
- dataEditable: false
1211
1323
  }));
1212
- const model = useTableModel({
1213
- rows,
1214
- view,
1215
- schema: jsonSchema,
1216
- projection,
1217
- features,
1218
- rowActions,
1219
- onCellUpdate: handleCellUpdate,
1220
- onRowOrderChange: handleRowOrderChange,
1221
- onRowAction
1222
- });
1223
- const presentation = useMemo6(() => {
1224
- if (model) {
1225
- return new TablePresentation(model);
1226
- }
1227
- }, [
1228
- model
1229
- ]);
1230
- return /* @__PURE__ */ React9.createElement("div", {
1231
- role: "none",
1232
- className: mx2("is-full bs-full grow grid", classNames)
1233
- }, /* @__PURE__ */ React9.createElement("div", {
1234
- role: "none",
1235
- className: "grid min-bs-0 overflow-hidden"
1236
- }, /* @__PURE__ */ React9.createElement(Table.Root, null, /* @__PURE__ */ React9.createElement(Table.Main, {
1237
- ref: tableRef,
1238
- model,
1239
- presentation,
1240
- ignoreAttention: true,
1241
- onRowClick
1242
- }))));
1243
- } finally {
1244
- _effect.f();
1245
- }
1246
- };
1247
-
1248
- // src/components/TableToolbar/TableToolbar.tsx
1249
- import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
1250
- import { Rx } from "@effect-rx/rx-react";
1251
- import React10, { useMemo as useMemo7 } from "react";
1252
- import { live as live2 } from "@dxos/live-object";
1253
- import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
1254
- import { rxFromSignal } from "@dxos/react-ui-menu";
1255
- var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.make((get) => {
1256
- const add = createMenuAction("add-row", onAdd, {
1257
- type: "add-row",
1258
- icon: "ph--plus--regular",
1259
- label: [
1260
- "add row",
1261
- {
1262
- ns: translationKey
1263
- }
1264
- ],
1265
- testId: "table.toolbar.add-row"
1266
- });
1267
- const save = createMenuAction("save-view", onSave, {
1268
- type: "save-view",
1269
- icon: "ph--floppy-disk--regular",
1270
- label: [
1271
- "save view label",
1272
- {
1273
- ns: translationKey
1274
- }
1275
- ],
1276
- testId: "table.toolbar.save-view",
1277
- iconOnly: false,
1278
- hidden: get(rxFromSignal(() => !state.viewDirty))
1279
- });
1280
- const gap = createGapSeparator();
1281
- const nodes = [
1282
- add,
1283
- save,
1284
- ...gap.nodes
1285
- ];
1286
- const edges = nodes.map(({ id: target }) => ({
1287
- source: "root",
1288
- target
1324
+ }, [
1325
+ registry,
1326
+ jsonSchema,
1327
+ properties
1328
+ ]);
1329
+ const tableRef = useRef3(null);
1330
+ const handleCellUpdate = useCallback5((cell) => {
1331
+ tableRef.current?.update?.(cell);
1332
+ }, []);
1333
+ const handleRowOrderChange = useCallback5(() => {
1334
+ tableRef.current?.update?.();
1335
+ }, []);
1336
+ const features = useDefaultValue(props.features, () => ({
1337
+ selection: {
1338
+ enabled: false
1339
+ },
1340
+ dataEditable: false
1289
1341
  }));
1290
- if (customActions) {
1291
- const custom = get(customActions);
1292
- nodes.push(...custom.nodes);
1293
- edges.push(...custom.edges);
1294
- }
1295
- return {
1296
- nodes,
1297
- edges
1298
- };
1299
- });
1300
- var TableToolbar = ({ classNames, viewDirty, attendableId, onAdd, onSave, customActions }) => {
1301
- var _effect = _useSignals10();
1302
- try {
1303
- const state = useMemo7(() => live2({
1304
- viewDirty
1305
- }), []);
1306
- const actionsCreator = useMemo7(() => createTableToolbarActions({
1307
- state,
1308
- onAdd,
1309
- onSave,
1310
- customActions
1311
- }), [
1312
- state,
1313
- onAdd,
1314
- onSave,
1315
- customActions
1316
- ]);
1317
- const menu = useMenuActions(actionsCreator);
1318
- return /* @__PURE__ */ React10.createElement(MenuProvider, {
1319
- ...menu,
1320
- attendableId
1321
- }, /* @__PURE__ */ React10.createElement(ToolbarMenu, {
1322
- classNames
1323
- }));
1324
- } finally {
1325
- _effect.f();
1326
- }
1342
+ const model = useTableModel({
1343
+ rows,
1344
+ object: dynamicTable?.object,
1345
+ projection: dynamicTable?.projection,
1346
+ features,
1347
+ rowActions,
1348
+ onCellUpdate: handleCellUpdate,
1349
+ onRowOrderChange: handleRowOrderChange,
1350
+ onRowAction
1351
+ });
1352
+ const presentation = useMemo6(() => {
1353
+ if (model) {
1354
+ return new TablePresentation(registry, model);
1355
+ }
1356
+ }, [
1357
+ registry,
1358
+ model
1359
+ ]);
1360
+ return /* @__PURE__ */ React9.createElement("div", {
1361
+ role: "none",
1362
+ className: mx2("w-full h-full grow grid", classNames)
1363
+ }, /* @__PURE__ */ React9.createElement("div", {
1364
+ role: "none",
1365
+ className: "grid min-h-0 overflow-hidden"
1366
+ }, /* @__PURE__ */ React9.createElement(Table.Root, null, /* @__PURE__ */ React9.createElement(Table.Main, {
1367
+ ref: tableRef,
1368
+ model,
1369
+ presentation,
1370
+ ignoreAttention: true,
1371
+ onRowClick
1372
+ }))));
1327
1373
  };
1328
1374
  export {
1329
1375
  BUTTON_IDENTIFIERS,
@@ -1337,8 +1383,12 @@ export {
1337
1383
  TablePresentation,
1338
1384
  TableToolbar,
1339
1385
  cellClassesForRowSelection,
1340
- createTable,
1386
+ compareValues,
1387
+ createDirectChangeCallback,
1388
+ createEchoChangeCallback,
1389
+ extractOrder,
1341
1390
  getBaseSchema,
1391
+ getSortValue,
1342
1392
  makeDynamicTable,
1343
1393
  narrowSchema,
1344
1394
  tableButtons,
@@ -1346,6 +1396,7 @@ export {
1346
1396
  touch,
1347
1397
  translations,
1348
1398
  useAddRow,
1399
+ useProjectionModel,
1349
1400
  useTableModel
1350
1401
  };
1351
1402
  //# sourceMappingURL=index.mjs.map