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