@dxos/react-ui-table 0.8.4-main.67995b8 → 0.8.4-main.69d29f4

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