@dxos/react-ui-table 0.7.4 → 0.7.5-labs.5f04cf6
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.
- package/dist/lib/browser/{chunk-IYCSJDMB.mjs → chunk-3FR6NHPD.mjs} +7 -5
- package/dist/lib/browser/chunk-3FR6NHPD.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1405 -1067
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types/index.mjs +1 -1
- package/dist/lib/node/{chunk-MHBMVCFZ.cjs → chunk-NB3SFHGA.cjs} +9 -7
- package/dist/lib/node/chunk-NB3SFHGA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +1409 -1051
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types/index.cjs +3 -3
- package/dist/lib/node/types/index.cjs.map +1 -1
- package/dist/lib/node-esm/{chunk-BMWGPXPL.mjs → chunk-RLVVOZW5.mjs} +7 -5
- package/dist/lib/node-esm/chunk-RLVVOZW5.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1405 -1067
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/types/index.mjs +1 -1
- package/dist/types/src/_deprecated/hooks/useColumnSorting.d.ts +1 -1
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +4 -3
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts +3 -2
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/CreateRefPanel.d.ts +3 -2
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +1 -1
- package/dist/types/src/components/Table/RefPanel.d.ts +4 -3
- package/dist/types/src/components/Table/RefPanel.d.ts.map +1 -1
- package/dist/types/src/components/Table/RowActionsMenu.d.ts +3 -2
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +2 -1
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +3 -2
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +18 -0
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +1 -0
- package/dist/types/src/components/TableToolbar/index.d.ts +2 -0
- package/dist/types/src/components/TableToolbar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +31 -71
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -0
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +6 -2
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +19 -31
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +22 -0
- package/dist/types/src/model/table-presentation.d.ts.map +1 -0
- package/dist/types/src/model/table-presentation.test.d.ts +2 -0
- package/dist/types/src/model/table-presentation.test.d.ts.map +1 -0
- package/dist/types/src/model/table-sorting.d.ts +53 -0
- package/dist/types/src/model/table-sorting.d.ts.map +1 -0
- package/dist/types/src/playwright/TableManager.d.ts +2 -1
- package/dist/types/src/playwright/TableManager.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/table.d.ts +46 -154
- package/dist/types/src/types/table.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/table-buttons.d.ts +63 -19
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts +32 -9
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/table.d.ts +3 -2
- package/dist/types/src/util/table.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +30 -29
- package/src/components/Table/ColumnActionsMenu.tsx +12 -12
- package/src/components/Table/ColumnSettings.tsx +11 -11
- package/src/components/Table/CreateRefPanel.tsx +13 -14
- package/src/components/Table/RefPanel.tsx +9 -9
- package/src/components/Table/RowActionsMenu.tsx +6 -7
- package/src/components/Table/Table.stories.tsx +67 -38
- package/src/components/Table/Table.tsx +239 -148
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +13 -12
- package/src/components/TableCellEditor/TableCellEditor.tsx +6 -4
- package/src/components/TableToolbar/TableToolbar.tsx +72 -0
- package/src/components/{Toolbar → TableToolbar}/index.ts +1 -1
- package/src/components/index.ts +1 -1
- package/src/components/testing.ts +10 -8
- package/src/index.ts +2 -0
- package/src/model/index.ts +1 -0
- package/src/model/modal-controller.ts +15 -48
- package/src/model/selection-model.ts +12 -1
- package/src/model/table-model.test.ts +4 -76
- package/src/model/table-model.ts +73 -304
- package/src/model/table-presentation.test.ts +102 -0
- package/src/model/table-presentation.ts +223 -0
- package/src/model/table-sorting.ts +201 -0
- package/src/playwright/TableManager.ts +5 -1
- package/src/playwright/smoke.spec.ts +94 -9
- package/src/translations.ts +2 -1
- package/src/types/table.ts +4 -4
- package/src/util/index.ts +1 -0
- package/src/util/table-buttons.ts +127 -48
- package/src/util/table-controls.ts +71 -7
- package/src/util/table.ts +93 -52
- package/dist/lib/browser/chunk-IYCSJDMB.mjs.map +0 -7
- package/dist/lib/node/chunk-MHBMVCFZ.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-BMWGPXPL.mjs.map +0 -7
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -21
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
- package/dist/types/src/components/Toolbar/common.d.ts +0 -14
- package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
- package/dist/types/src/components/Toolbar/index.d.ts +0 -2
- package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
- package/src/components/Toolbar/Toolbar.tsx +0 -87
- package/src/components/Toolbar/common.tsx +0 -71
|
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module';const require = createRequire(import
|
|
|
2
2
|
import {
|
|
3
3
|
TableSchema,
|
|
4
4
|
TableType
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RLVVOZW5.mjs";
|
|
6
6
|
|
|
7
7
|
// packages/ui/react-ui-table/src/translations.ts
|
|
8
8
|
var translationKey = "table";
|
|
@@ -18,7 +18,7 @@ var translations_default = [
|
|
|
18
18
|
"new schema": "New schema",
|
|
19
19
|
"continue label": "Continue",
|
|
20
20
|
"create stack section label": "Create table",
|
|
21
|
-
"add row": "Add row",
|
|
21
|
+
"add row label": "Add row",
|
|
22
22
|
"create comment": "Create thread",
|
|
23
23
|
"column action sort descending": "Sort Descending",
|
|
24
24
|
"column action sort ascending": "Sort Ascending",
|
|
@@ -29,55 +29,56 @@ var translations_default = [
|
|
|
29
29
|
"bulk delete row label": "Delete selected rows",
|
|
30
30
|
"column deleted label": "Column deleted",
|
|
31
31
|
"new column button label": "Create column",
|
|
32
|
-
"create new object label": "Create new object \u201C{{text}}\u201D"
|
|
32
|
+
"create new object label": "Create new object \u201C{{text}}\u201D",
|
|
33
|
+
"save view label": "Save changes to view"
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
];
|
|
37
38
|
|
|
38
39
|
// packages/ui/react-ui-table/src/components/Table/Table.tsx
|
|
39
|
-
import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2 } from "react";
|
|
40
|
-
import { getValue } from "@dxos/echo-schema";
|
|
41
|
-
import { invariant as
|
|
40
|
+
import React7, { forwardRef, useCallback as useCallback4, useImperativeHandle, useState as useState2, useMemo as useMemo4 } from "react";
|
|
41
|
+
import { getValue as getValue4 } from "@dxos/echo-schema";
|
|
42
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
42
43
|
import { Filter, getSpace as getSpace4, fullyQualifiedId } from "@dxos/react-client/echo";
|
|
43
44
|
import { useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
44
45
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
45
46
|
import { Grid, closestCell } from "@dxos/react-ui-grid";
|
|
46
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
47
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
47
48
|
import { isNotFalsy } from "@dxos/util";
|
|
48
49
|
|
|
49
50
|
// packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
|
|
50
51
|
import React from "react";
|
|
51
52
|
import { DropdownMenu, useTranslation } from "@dxos/react-ui";
|
|
52
|
-
var ColumnActionsMenu = ({ model }) => {
|
|
53
|
+
var ColumnActionsMenu = ({ model, modals }) => {
|
|
53
54
|
const { t } = useTranslation(translationKey);
|
|
54
|
-
const state =
|
|
55
|
-
if (
|
|
55
|
+
const state = modals.state.value;
|
|
56
|
+
if (state?.type !== "column") {
|
|
56
57
|
return null;
|
|
57
58
|
}
|
|
58
|
-
const currentSort = model.sorting;
|
|
59
|
+
const currentSort = model.sorting?.sorting;
|
|
59
60
|
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
60
61
|
return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
|
|
61
62
|
modal: false,
|
|
62
|
-
open:
|
|
63
|
-
onOpenChange:
|
|
63
|
+
open: true,
|
|
64
|
+
onOpenChange: modals.close
|
|
64
65
|
}, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
|
|
65
|
-
virtualRef:
|
|
66
|
+
virtualRef: modals.trigger
|
|
66
67
|
}), /* @__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, {
|
|
67
68
|
"data-testid": "column-sort-descending",
|
|
68
|
-
onClick: () => model.setSort(state.fieldId, "desc")
|
|
69
|
+
onClick: () => model.sorting?.setSort(state.fieldId, "desc")
|
|
69
70
|
}, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
70
71
|
"data-testid": "column-sort-ascending",
|
|
71
|
-
onClick: () => model.setSort(state.fieldId, "asc")
|
|
72
|
+
onClick: () => model.sorting?.setSort(state.fieldId, "asc")
|
|
72
73
|
}, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
73
74
|
"data-testid": "column-clear-sort",
|
|
74
|
-
onClick: () => model.clearSort()
|
|
75
|
+
onClick: () => model.sorting?.clearSort()
|
|
75
76
|
}, t("column action clear sorting")), model.getColumnCount() > 1 && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
76
77
|
"data-testid": "column-delete",
|
|
77
78
|
onClick: () => model.deleteColumn(state.fieldId)
|
|
78
79
|
}, t("column action delete")), /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
79
80
|
"data-testid": "column-settings",
|
|
80
|
-
onClick: () =>
|
|
81
|
+
onClick: () => modals.openColumnSettings()
|
|
81
82
|
}, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
|
|
82
83
|
};
|
|
83
84
|
|
|
@@ -86,9 +87,9 @@ import React2, { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
86
87
|
import { getSpace } from "@dxos/react-client/echo";
|
|
87
88
|
import { DropdownMenu as DropdownMenu2 } from "@dxos/react-ui";
|
|
88
89
|
import { FieldEditor } from "@dxos/react-ui-form";
|
|
89
|
-
var ColumnSettings = ({ model, onNewColumn }) => {
|
|
90
|
+
var ColumnSettings = ({ model, modals, onNewColumn }) => {
|
|
90
91
|
const [newField, setNewField] = useState();
|
|
91
|
-
const state =
|
|
92
|
+
const state = modals.state.value;
|
|
92
93
|
const space = getSpace(model?.table);
|
|
93
94
|
useEffect(() => {
|
|
94
95
|
if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
|
|
@@ -107,19 +108,19 @@ var ColumnSettings = ({ model, onNewColumn }) => {
|
|
|
107
108
|
if (state?.type === "columnSettings") {
|
|
108
109
|
const { mode } = state;
|
|
109
110
|
if (mode.type === "edit") {
|
|
110
|
-
return model?.table?.view?.fields.find((f) => f.id === mode.fieldId);
|
|
111
|
+
return model?.table?.view?.target?.fields.find((f) => f.id === mode.fieldId);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
return void 0;
|
|
114
115
|
}, [
|
|
115
|
-
model?.table?.view?.fields,
|
|
116
|
+
model?.table?.view?.target?.fields,
|
|
116
117
|
state
|
|
117
118
|
]);
|
|
118
119
|
const field = existingField ?? newField;
|
|
119
120
|
const handleSave = useCallback(() => {
|
|
120
|
-
|
|
121
|
+
modals.close();
|
|
121
122
|
}, [
|
|
122
|
-
|
|
123
|
+
modals
|
|
123
124
|
]);
|
|
124
125
|
const handleCancel = useCallback(() => {
|
|
125
126
|
if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
|
|
@@ -130,18 +131,18 @@ var ColumnSettings = ({ model, onNewColumn }) => {
|
|
|
130
131
|
state,
|
|
131
132
|
newField
|
|
132
133
|
]);
|
|
133
|
-
if (!model?.table?.view || !model.projection || !field) {
|
|
134
|
+
if (!model?.table?.view?.target || !model.projection || !field) {
|
|
134
135
|
return null;
|
|
135
136
|
}
|
|
136
137
|
return /* @__PURE__ */ React2.createElement(DropdownMenu2.Root, {
|
|
137
138
|
modal: false,
|
|
138
139
|
open: state?.type === "columnSettings"
|
|
139
140
|
}, /* @__PURE__ */ React2.createElement(DropdownMenu2.VirtualTrigger, {
|
|
140
|
-
virtualRef:
|
|
141
|
+
virtualRef: modals.trigger
|
|
141
142
|
}), /* @__PURE__ */ React2.createElement(DropdownMenu2.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu2.Content, {
|
|
142
143
|
classNames: "md:is-64"
|
|
143
144
|
}, /* @__PURE__ */ React2.createElement(DropdownMenu2.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
|
|
144
|
-
view: model.table.view,
|
|
145
|
+
view: model.table.view.target,
|
|
145
146
|
projection: model.projection,
|
|
146
147
|
field,
|
|
147
148
|
registry: space?.db.schemaRegistry,
|
|
@@ -157,15 +158,17 @@ import { create, getSpace as getSpace2 } from "@dxos/react-client/echo";
|
|
|
157
158
|
import { Popover } from "@dxos/react-ui";
|
|
158
159
|
import { Form } from "@dxos/react-ui-form";
|
|
159
160
|
import { useGridContext } from "@dxos/react-ui-grid";
|
|
160
|
-
var CreateRefPanel = ({ model, __gridScope }) => {
|
|
161
|
+
var CreateRefPanel = ({ model, modals, __gridScope }) => {
|
|
161
162
|
const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
|
|
162
163
|
const space = getSpace2(model?.table);
|
|
163
|
-
const state =
|
|
164
|
+
const state = modals.state.value;
|
|
164
165
|
const schema = useMemo2(() => {
|
|
165
166
|
if (!space || state?.type !== "createRefPanel") {
|
|
166
167
|
return;
|
|
167
168
|
}
|
|
168
|
-
const schema2 = space.db.schemaRegistry.
|
|
169
|
+
const [schema2] = space.db.schemaRegistry.query({
|
|
170
|
+
typename: state.typename
|
|
171
|
+
}).runSync();
|
|
169
172
|
if (schema2) {
|
|
170
173
|
const omit = S.omit("id");
|
|
171
174
|
return omit(schema2);
|
|
@@ -178,23 +181,25 @@ var CreateRefPanel = ({ model, __gridScope }) => {
|
|
|
178
181
|
if (!model || !space || state?.type !== "createRefPanel") {
|
|
179
182
|
return;
|
|
180
183
|
}
|
|
181
|
-
const schema2 = space.db.schemaRegistry.
|
|
184
|
+
const [schema2] = space.db.schemaRegistry.query({
|
|
185
|
+
typename: state.typename
|
|
186
|
+
}).runSync();
|
|
182
187
|
if (schema2) {
|
|
183
188
|
const obj = space.db.add(create(schema2, values));
|
|
184
189
|
state.onCreate?.(obj);
|
|
185
190
|
}
|
|
186
|
-
void
|
|
191
|
+
void modals.close();
|
|
187
192
|
}, [
|
|
188
|
-
|
|
193
|
+
modals,
|
|
189
194
|
space,
|
|
190
195
|
state
|
|
191
196
|
]);
|
|
192
197
|
const handleCancel = useCallback2(() => {
|
|
193
198
|
if (model) {
|
|
194
|
-
|
|
199
|
+
modals.close();
|
|
195
200
|
}
|
|
196
201
|
}, [
|
|
197
|
-
|
|
202
|
+
modals
|
|
198
203
|
]);
|
|
199
204
|
if (!model?.table?.view || !model.projection) {
|
|
200
205
|
return null;
|
|
@@ -204,11 +209,11 @@ var CreateRefPanel = ({ model, __gridScope }) => {
|
|
|
204
209
|
open: state?.type === "createRefPanel" && !!schema,
|
|
205
210
|
onOpenChange: (nextOpen) => {
|
|
206
211
|
if (model && !nextOpen) {
|
|
207
|
-
return
|
|
212
|
+
return modals.close();
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
}, /* @__PURE__ */ React3.createElement(Popover.VirtualTrigger, {
|
|
211
|
-
virtualRef:
|
|
216
|
+
virtualRef: modals.trigger
|
|
212
217
|
}), /* @__PURE__ */ React3.createElement(Popover.Portal, null, /* @__PURE__ */ React3.createElement(Popover.Content, {
|
|
213
218
|
classNames: "md:is-64",
|
|
214
219
|
"data-grid": gridId
|
|
@@ -232,24 +237,24 @@ var getRefTargetObj = (space, id) => {
|
|
|
232
237
|
return void 0;
|
|
233
238
|
}
|
|
234
239
|
};
|
|
235
|
-
var RefPanel = ({ model }) => {
|
|
236
|
-
const state =
|
|
237
|
-
const space = getSpace3(model
|
|
240
|
+
var RefPanel = ({ model, modals }) => {
|
|
241
|
+
const state = modals.state.value;
|
|
242
|
+
const space = getSpace3(model.table);
|
|
238
243
|
const targetObj = getRefTargetObj(space, state?.type === "refPanel" ? state.targetId : void 0);
|
|
239
244
|
const schema = space && state?.type === "refPanel" ? space.db.schemaRegistry.getSchema(state.typename) : void 0;
|
|
240
|
-
if (!model
|
|
245
|
+
if (!model.table?.view || !model.projection) {
|
|
241
246
|
return null;
|
|
242
247
|
}
|
|
243
248
|
return /* @__PURE__ */ React4.createElement(Popover2.Root, {
|
|
244
249
|
modal: false,
|
|
245
250
|
open: state?.type === "refPanel" && !!targetObj && !!schema,
|
|
246
251
|
onOpenChange: (nextOpen) => {
|
|
247
|
-
if (
|
|
248
|
-
return
|
|
252
|
+
if (!nextOpen) {
|
|
253
|
+
return modals.close();
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
}, /* @__PURE__ */ React4.createElement(Popover2.VirtualTrigger, {
|
|
252
|
-
virtualRef:
|
|
257
|
+
virtualRef: modals.trigger
|
|
253
258
|
}), /* @__PURE__ */ React4.createElement(Popover2.Portal, null, /* @__PURE__ */ React4.createElement(Popover2.Content, {
|
|
254
259
|
classNames: "md:is-64"
|
|
255
260
|
}, targetObj && schema && /* @__PURE__ */ React4.createElement(Form2, {
|
|
@@ -262,762 +267,319 @@ var RefPanel = ({ model }) => {
|
|
|
262
267
|
// packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
|
|
263
268
|
import React5 from "react";
|
|
264
269
|
import { DropdownMenu as DropdownMenu3, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
265
|
-
var RowActionsMenu = ({ model }) => {
|
|
270
|
+
var RowActionsMenu = ({ model, modals }) => {
|
|
266
271
|
const { t } = useTranslation2(translationKey);
|
|
267
272
|
const hasSelection = model.selection.hasSelection.value;
|
|
268
|
-
const state =
|
|
273
|
+
const state = modals.state.value;
|
|
269
274
|
if (state?.type !== "row") {
|
|
270
275
|
return null;
|
|
271
276
|
}
|
|
272
277
|
return /* @__PURE__ */ React5.createElement(DropdownMenu3.Root, {
|
|
273
278
|
modal: false,
|
|
274
279
|
open: true,
|
|
275
|
-
onOpenChange:
|
|
280
|
+
onOpenChange: modals.close
|
|
276
281
|
}, /* @__PURE__ */ React5.createElement(DropdownMenu3.VirtualTrigger, {
|
|
277
|
-
virtualRef:
|
|
282
|
+
virtualRef: modals.trigger
|
|
278
283
|
}), /* @__PURE__ */ React5.createElement(DropdownMenu3.Content, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Viewport, null, /* @__PURE__ */ React5.createElement(DropdownMenu3.Item, {
|
|
279
284
|
"data-testid": "row-menu-delete",
|
|
280
285
|
onClick: () => model.deleteRow(state.rowIndex)
|
|
281
286
|
}, t(hasSelection ? "bulk delete row label" : "delete row label"))), /* @__PURE__ */ React5.createElement(DropdownMenu3.Arrow, null)));
|
|
282
287
|
};
|
|
283
288
|
|
|
284
|
-
// packages/ui/react-ui-table/src/
|
|
285
|
-
import
|
|
286
|
-
import {
|
|
289
|
+
// packages/ui/react-ui-table/src/model/table-model.ts
|
|
290
|
+
import { computed as computed3, effect as effect2, signal as signal3 } from "@preact/signals-core";
|
|
291
|
+
import { Resource as Resource2 } from "@dxos/context";
|
|
292
|
+
import { FormatEnum as FormatEnum3, getValue as getValue2, setValue } from "@dxos/echo-schema";
|
|
287
293
|
import { invariant } from "@dxos/invariant";
|
|
288
|
-
import {
|
|
294
|
+
import { isReactiveObject, makeRef as makeRef2 } from "@dxos/live-object";
|
|
295
|
+
import { PublicKey as PublicKey2 } from "@dxos/react-client";
|
|
296
|
+
import { formatForEditing, parseValue } from "@dxos/react-ui-form";
|
|
289
297
|
|
|
290
|
-
// packages/ui/react-ui-table/src/
|
|
291
|
-
import {
|
|
292
|
-
import {
|
|
293
|
-
var completion = ({ debug, onQuery, onMatch }) => {
|
|
294
|
-
return [
|
|
295
|
-
EditorView.theme({
|
|
296
|
-
".cm-completionDialog": {
|
|
297
|
-
width: "var(--dx-gridCellWidth)"
|
|
298
|
-
}
|
|
299
|
-
}),
|
|
300
|
-
autocompletion({
|
|
301
|
-
icons: false,
|
|
302
|
-
activateOnTyping: true,
|
|
303
|
-
closeOnBlur: !debug,
|
|
304
|
-
override: [
|
|
305
|
-
async (context) => {
|
|
306
|
-
const text = context.state.doc.toString();
|
|
307
|
-
return {
|
|
308
|
-
from: 0,
|
|
309
|
-
options: await onQuery(text)
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
],
|
|
313
|
-
// TODO(burdon): Consts from grid (to line-up with grid).
|
|
314
|
-
tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
|
|
315
|
-
optionClass: () => "flex h-[33px] items-center"
|
|
316
|
-
}),
|
|
317
|
-
// Check for accepted completion metadata in the transaction.
|
|
318
|
-
EditorView.updateListener.of((update) => {
|
|
319
|
-
update.transactions.forEach((tr) => {
|
|
320
|
-
const completion2 = tr.annotation(pickedCompletion);
|
|
321
|
-
if (completion2) {
|
|
322
|
-
onMatch(completion2.data);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
})
|
|
326
|
-
];
|
|
327
|
-
};
|
|
298
|
+
// packages/ui/react-ui-table/src/model/selection-model.ts
|
|
299
|
+
import { computed, effect, signal } from "@preact/signals-core";
|
|
300
|
+
import { Resource } from "@dxos/context";
|
|
328
301
|
|
|
329
|
-
// packages/ui/react-ui-table/src/
|
|
330
|
-
var
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
var
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
302
|
+
// packages/ui/react-ui-table/src/util/signals.ts
|
|
303
|
+
var touch = (value) => value;
|
|
304
|
+
|
|
305
|
+
// packages/ui/react-ui-table/src/util/table.ts
|
|
306
|
+
import { AST, Format, FormatEnum, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
|
|
307
|
+
import { PublicKey } from "@dxos/react-client";
|
|
308
|
+
import { create as create2, makeRef } from "@dxos/react-client/echo";
|
|
309
|
+
import { createFieldId, createView, getSchemaProperties, ViewProjection } from "@dxos/schema";
|
|
310
|
+
var initializeTable = async ({ space, table, initialRow = true, initialSchema }) => {
|
|
311
|
+
if (initialSchema) {
|
|
312
|
+
const schema = await space.db.schemaRegistry.query({
|
|
313
|
+
typename: initialSchema
|
|
314
|
+
}).firstOrUndefined();
|
|
315
|
+
if (!schema) {
|
|
316
|
+
throw new Error(`Schema not found: ${initialSchema}`);
|
|
343
317
|
}
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
318
|
+
const fields = getSchemaProperties(schema.ast).filter((prop) => prop.type !== "object" || prop.format === FormatEnum.Ref).map((prop) => prop.name);
|
|
319
|
+
table.view = makeRef(createView({
|
|
320
|
+
// TODO(ZaymonFC): Don't hardcode name?
|
|
321
|
+
name: "View",
|
|
322
|
+
typename: schema.typename,
|
|
323
|
+
jsonSchema: schema.jsonSchema,
|
|
324
|
+
fields
|
|
325
|
+
}));
|
|
326
|
+
return schema;
|
|
327
|
+
} else {
|
|
328
|
+
const ContactSchema = TypedObject({
|
|
329
|
+
typename: `example.com/type/${PublicKey.random().truncate()}`,
|
|
330
|
+
version: "0.1.0"
|
|
331
|
+
})({
|
|
332
|
+
name: S2.optional(S2.String).annotations({
|
|
333
|
+
[AST.TitleAnnotationId]: "Name"
|
|
334
|
+
}),
|
|
335
|
+
active: S2.optional(S2.Boolean),
|
|
336
|
+
email: S2.optional(Format.Email),
|
|
337
|
+
salary: S2.optional(Format.Currency()).annotations({
|
|
338
|
+
[AST.TitleAnnotationId]: "Salary"
|
|
339
|
+
})
|
|
340
|
+
});
|
|
341
|
+
const [contactSchema] = await space.db.schemaRegistry.register([
|
|
342
|
+
ContactSchema
|
|
343
|
+
]);
|
|
344
|
+
table.view = makeRef(createView({
|
|
345
|
+
name: "View",
|
|
346
|
+
typename: contactSchema.typename,
|
|
347
|
+
jsonSchema: contactSchema.jsonSchema,
|
|
348
|
+
fields: [
|
|
349
|
+
"name",
|
|
350
|
+
"email",
|
|
351
|
+
"salary",
|
|
352
|
+
"active"
|
|
354
353
|
]
|
|
354
|
+
}));
|
|
355
|
+
const projection = new ViewProjection(contactSchema, table.view.target);
|
|
356
|
+
projection.setFieldProjection({
|
|
357
|
+
field: {
|
|
358
|
+
id: table.view.target.fields.find((f) => f.path === "salary").id,
|
|
359
|
+
path: "salary",
|
|
360
|
+
size: 150
|
|
361
|
+
}
|
|
355
362
|
});
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const handleEnter = useCallback3((value) => {
|
|
362
|
-
if (!model || !editing) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const cell = parseCellIndex(editing.index);
|
|
366
|
-
model.setCellData(cell, value);
|
|
367
|
-
onEnter?.(cell);
|
|
368
|
-
onFocus?.();
|
|
369
|
-
setEditing(null);
|
|
370
|
-
}, [
|
|
371
|
-
model,
|
|
372
|
-
editing
|
|
373
|
-
]);
|
|
374
|
-
const handleBlur = useCallback3((value) => {
|
|
375
|
-
if (!model || !editing) {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
if (suppressNextBlur.current) {
|
|
379
|
-
suppressNextBlur.current = false;
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
const cell = parseCellIndex(editing.index);
|
|
383
|
-
if (value !== void 0) {
|
|
384
|
-
model.setCellData(cell, value);
|
|
385
|
-
}
|
|
386
|
-
}, [
|
|
387
|
-
model,
|
|
388
|
-
editing
|
|
389
|
-
]);
|
|
390
|
-
const handleClose = useCallback3((value, event) => {
|
|
391
|
-
if (!model || !editing || !fieldProjection) {
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
const cell = parseCellIndex(editing.index);
|
|
395
|
-
onEnter?.(cell);
|
|
396
|
-
if (event && onFocus) {
|
|
397
|
-
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
398
|
-
}
|
|
399
|
-
}, [
|
|
400
|
-
model,
|
|
401
|
-
editing,
|
|
402
|
-
onFocus,
|
|
403
|
-
onEnter,
|
|
404
|
-
fieldProjection,
|
|
405
|
-
determineNavigationAxis,
|
|
406
|
-
determineNavigationDelta
|
|
407
|
-
]);
|
|
408
|
-
const extension = useMemo3(() => {
|
|
409
|
-
if (!fieldProjection) {
|
|
410
|
-
return [];
|
|
411
|
-
}
|
|
412
|
-
const extension2 = [
|
|
413
|
-
editorKeys({
|
|
414
|
-
onClose: handleClose,
|
|
415
|
-
...editing?.initialContent && {
|
|
416
|
-
onNav: handleClose
|
|
417
|
-
}
|
|
418
|
-
})
|
|
419
|
-
];
|
|
420
|
-
if (onQuery) {
|
|
421
|
-
switch (fieldProjection.props.format) {
|
|
422
|
-
case FormatEnum.Ref: {
|
|
423
|
-
extension2.push([
|
|
424
|
-
completion({
|
|
425
|
-
onQuery: (text) => onQuery(fieldProjection, text),
|
|
426
|
-
onMatch: (data) => {
|
|
427
|
-
if (model && editing) {
|
|
428
|
-
if (isCreateOption(data)) {
|
|
429
|
-
const { field, props } = fieldProjection;
|
|
430
|
-
if (props.referenceSchema) {
|
|
431
|
-
suppressNextBlur.current = true;
|
|
432
|
-
model.modalController.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
|
|
433
|
-
[field.referencePath]: data.text
|
|
434
|
-
}, (data2) => {
|
|
435
|
-
handleEnter(data2);
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
} else {
|
|
439
|
-
handleEnter(data);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
})
|
|
444
|
-
]);
|
|
445
|
-
break;
|
|
446
|
-
}
|
|
363
|
+
projection.setFieldProjection({
|
|
364
|
+
field: {
|
|
365
|
+
id: table.view.target.fields.find((f) => f.path === "active").id,
|
|
366
|
+
path: "active",
|
|
367
|
+
size: 100
|
|
447
368
|
}
|
|
369
|
+
});
|
|
370
|
+
projection.setFieldProjection({
|
|
371
|
+
field: {
|
|
372
|
+
id: createFieldId(),
|
|
373
|
+
path: "manager",
|
|
374
|
+
referencePath: "name"
|
|
375
|
+
},
|
|
376
|
+
props: {
|
|
377
|
+
property: "manager",
|
|
378
|
+
type: TypeEnum.Ref,
|
|
379
|
+
format: FormatEnum.Ref,
|
|
380
|
+
referenceSchema: contactSchema.typename,
|
|
381
|
+
title: "Manager"
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
if (initialRow) {
|
|
385
|
+
space.db.add(create2(contactSchema, {}));
|
|
448
386
|
}
|
|
449
|
-
return
|
|
450
|
-
}, [
|
|
451
|
-
model,
|
|
452
|
-
editing,
|
|
453
|
-
fieldProjection,
|
|
454
|
-
handleClose
|
|
455
|
-
]);
|
|
456
|
-
const getCellContent = useCallback3(() => {
|
|
457
|
-
if (model && editing) {
|
|
458
|
-
const value = model.getCellData(parseCellIndex(editing.index));
|
|
459
|
-
return value !== void 0 ? String(value) : "";
|
|
460
|
-
}
|
|
461
|
-
}, [
|
|
462
|
-
model,
|
|
463
|
-
editing
|
|
464
|
-
]);
|
|
465
|
-
return /* @__PURE__ */ React6.createElement(GridCellEditor, {
|
|
466
|
-
extension,
|
|
467
|
-
getCellContent,
|
|
468
|
-
onBlur: handleBlur
|
|
469
|
-
});
|
|
470
|
-
};
|
|
471
|
-
var determineNavigationAxis = ({ key }) => {
|
|
472
|
-
switch (key) {
|
|
473
|
-
case "ArrowUp":
|
|
474
|
-
case "ArrowDown":
|
|
475
|
-
case "Enter": {
|
|
476
|
-
return "row";
|
|
477
|
-
}
|
|
478
|
-
case "ArrowLeft":
|
|
479
|
-
case "ArrowRight":
|
|
480
|
-
case "Tab":
|
|
481
|
-
return "col";
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
var determineNavigationDelta = ({ key, shift }) => {
|
|
485
|
-
switch (key) {
|
|
486
|
-
case "ArrowUp":
|
|
487
|
-
case "ArrowLeft":
|
|
488
|
-
return -1;
|
|
489
|
-
case "ArrowDown":
|
|
490
|
-
case "ArrowRight":
|
|
491
|
-
return 1;
|
|
387
|
+
return contactSchema;
|
|
492
388
|
}
|
|
493
|
-
return shift ? -1 : 1;
|
|
494
389
|
};
|
|
495
390
|
|
|
496
|
-
// packages/ui/react-ui-table/src/
|
|
497
|
-
var
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
frozenColsEnd: 1
|
|
391
|
+
// packages/ui/react-ui-table/src/util/table-buttons.ts
|
|
392
|
+
var BUTTON_IDENTIFIERS = {
|
|
393
|
+
columnSettings: "data-table-column-settings-button",
|
|
394
|
+
newColumn: "data-table-new-column-button",
|
|
395
|
+
referencedCell: "data-table-ref-cell-button",
|
|
396
|
+
rowMenu: "data-table-row-menu-button",
|
|
397
|
+
sort: "data-table-sort-button"
|
|
504
398
|
};
|
|
505
|
-
var
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}, children);
|
|
399
|
+
var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
|
|
400
|
+
const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
401
|
+
const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
|
|
402
|
+
return `<button ${attr} data-testid="${testId}" class="ch-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${icon}"/></svg></button>`;
|
|
510
403
|
};
|
|
511
|
-
var
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
update: (cell) => {
|
|
522
|
-
if (cell) {
|
|
523
|
-
dxGrid.updateIfWithinBounds(cell);
|
|
524
|
-
} else {
|
|
525
|
-
dxGrid.updateCells(true);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
}, [
|
|
530
|
-
model,
|
|
531
|
-
dxGrid
|
|
532
|
-
]);
|
|
533
|
-
const handleFocus = useCallback4((increment, delta) => {
|
|
534
|
-
if (dxGrid) {
|
|
535
|
-
dxGrid.refocus(increment, delta);
|
|
536
|
-
}
|
|
537
|
-
}, [
|
|
538
|
-
dxGrid
|
|
539
|
-
]);
|
|
540
|
-
const handleEnter = useCallback4((cell) => {
|
|
541
|
-
if (model && cell.row === model.getRowCount() - 1) {
|
|
542
|
-
model.insertRow(cell.row);
|
|
543
|
-
if (dxGrid) {
|
|
544
|
-
requestAnimationFrame(() => {
|
|
545
|
-
dxGrid?.scrollToRow(cell.row + 1);
|
|
546
|
-
dxGrid?.refocus("row", 1);
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}, [
|
|
551
|
-
model,
|
|
552
|
-
dxGrid
|
|
553
|
-
]);
|
|
554
|
-
const handleKeyDown = useCallback4((event) => {
|
|
555
|
-
const cell = closestCell(event.target);
|
|
556
|
-
if (!model || !cell) {
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
switch (event.key) {
|
|
560
|
-
case "Backspace":
|
|
561
|
-
case "Delete": {
|
|
562
|
-
model.setCellData(cell, void 0);
|
|
563
|
-
break;
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}, [
|
|
567
|
-
model
|
|
568
|
-
]);
|
|
569
|
-
const handleAxisResize = useCallback4((event) => {
|
|
570
|
-
if (event.axis === "col") {
|
|
571
|
-
const columnIndex = parseInt(event.index, 10);
|
|
572
|
-
model?.setColumnWidth(columnIndex, event.size);
|
|
573
|
-
}
|
|
574
|
-
}, [
|
|
575
|
-
model
|
|
576
|
-
]);
|
|
577
|
-
const handleWheel = useCallback4((event) => {
|
|
578
|
-
if (!ignoreAttention && !hasAttention) {
|
|
579
|
-
event.stopPropagation();
|
|
580
|
-
}
|
|
581
|
-
}, [
|
|
582
|
-
hasAttention,
|
|
583
|
-
ignoreAttention
|
|
584
|
-
]);
|
|
585
|
-
const handleNewColumn = useCallback4(() => {
|
|
586
|
-
const columns = model?.getColumnCount();
|
|
587
|
-
if (dxGrid && columns) {
|
|
588
|
-
dxGrid.scrollToColumn(columns - 1);
|
|
589
|
-
}
|
|
590
|
-
}, [
|
|
591
|
-
model,
|
|
592
|
-
dxGrid
|
|
593
|
-
]);
|
|
594
|
-
const handleQuery = useCallback4(async ({ field, props }, text) => {
|
|
595
|
-
if (model && props.referenceSchema && field.referencePath) {
|
|
596
|
-
const space = getSpace4(model.table);
|
|
597
|
-
invariant2(space, void 0, {
|
|
598
|
-
F: __dxlog_file2,
|
|
599
|
-
L: 180,
|
|
600
|
-
S: void 0,
|
|
601
|
-
A: [
|
|
602
|
-
"space",
|
|
603
|
-
""
|
|
604
|
-
]
|
|
605
|
-
});
|
|
606
|
-
const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
|
|
607
|
-
if (schema) {
|
|
608
|
-
const { objects } = await space.db.query(Filter.schema(schema)).run();
|
|
609
|
-
const options = objects.map((obj) => {
|
|
610
|
-
const value = getValue(obj, field.referencePath);
|
|
611
|
-
if (!value || typeof value !== "string") {
|
|
612
|
-
return void 0;
|
|
613
|
-
}
|
|
614
|
-
return {
|
|
615
|
-
label: value,
|
|
616
|
-
data: obj
|
|
617
|
-
};
|
|
618
|
-
}).filter(isNotFalsy);
|
|
619
|
-
return [
|
|
620
|
-
...options,
|
|
621
|
-
{
|
|
622
|
-
label: t("create new object label", {
|
|
623
|
-
text
|
|
624
|
-
}),
|
|
625
|
-
data: createOption(text)
|
|
626
|
-
}
|
|
627
|
-
];
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
return [];
|
|
631
|
-
}, [
|
|
632
|
-
model
|
|
633
|
-
]);
|
|
634
|
-
if (!model) {
|
|
635
|
-
return /* @__PURE__ */ React7.createElement("span", {
|
|
636
|
-
role: "none",
|
|
637
|
-
className: "attention-surface"
|
|
404
|
+
var addColumnButton = {
|
|
405
|
+
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
406
|
+
icon: "ph--plus--regular",
|
|
407
|
+
render: ({ disabled }) => {
|
|
408
|
+
return createButton({
|
|
409
|
+
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
410
|
+
icon: addColumnButton.icon,
|
|
411
|
+
disabled,
|
|
412
|
+
data: {},
|
|
413
|
+
testId: "table-new-column-button"
|
|
638
414
|
});
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
model,
|
|
644
|
-
onEnter: handleEnter,
|
|
645
|
-
onFocus: handleFocus,
|
|
646
|
-
onQuery: handleQuery
|
|
647
|
-
}), /* @__PURE__ */ React7.createElement(Grid.Content, {
|
|
648
|
-
onWheelCapture: handleWheel,
|
|
649
|
-
className: mx("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
|
|
650
|
-
frozen,
|
|
651
|
-
columns: model.columnMeta.value,
|
|
652
|
-
limitRows: model.getRowCount() ?? 0,
|
|
653
|
-
limitColumns: model.table.view?.fields?.length ?? 0,
|
|
654
|
-
onAxisResize: handleAxisResize,
|
|
655
|
-
onClick: model?.handleGridClick,
|
|
656
|
-
onKeyDown: handleKeyDown,
|
|
657
|
-
overscroll: "trap",
|
|
658
|
-
ref: setDxGrid
|
|
659
|
-
}), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
|
|
660
|
-
model
|
|
661
|
-
}), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
|
|
662
|
-
model
|
|
663
|
-
}), /* @__PURE__ */ React7.createElement(ColumnSettings, {
|
|
664
|
-
model,
|
|
665
|
-
onNewColumn: handleNewColumn
|
|
666
|
-
}), /* @__PURE__ */ React7.createElement(RefPanel, {
|
|
667
|
-
model
|
|
668
|
-
}), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
|
|
669
|
-
model
|
|
670
|
-
}));
|
|
671
|
-
});
|
|
672
|
-
var Table = {
|
|
673
|
-
Root: TableRoot,
|
|
674
|
-
Main: TableMain
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
// packages/ui/react-ui-table/src/components/Toolbar/Toolbar.tsx
|
|
678
|
-
import { createContext } from "@radix-ui/react-context";
|
|
679
|
-
import React9 from "react";
|
|
680
|
-
import { Toolbar as NaturalToolbar2, useTranslation as useTranslation4 } from "@dxos/react-ui";
|
|
681
|
-
|
|
682
|
-
// packages/ui/react-ui-table/src/components/Toolbar/common.tsx
|
|
683
|
-
import React8 from "react";
|
|
684
|
-
import { Icon, Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
|
|
685
|
-
var buttonStyles = "min-bs-0 p-2";
|
|
686
|
-
var tooltipProps = {
|
|
687
|
-
side: "top",
|
|
688
|
-
classNames: "z-10"
|
|
415
|
+
},
|
|
416
|
+
getData: (_el) => ({
|
|
417
|
+
type: "newColumn"
|
|
418
|
+
})
|
|
689
419
|
};
|
|
690
|
-
var
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
})
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}
|
|
420
|
+
var columnSettingsButton = {
|
|
421
|
+
attr: BUTTON_IDENTIFIERS.columnSettings,
|
|
422
|
+
icon: "ph--caret-down--regular",
|
|
423
|
+
render: ({ fieldId }) => {
|
|
424
|
+
return createButton({
|
|
425
|
+
attr: BUTTON_IDENTIFIERS.columnSettings,
|
|
426
|
+
icon: columnSettingsButton.icon,
|
|
427
|
+
data: {
|
|
428
|
+
"data-field-id": fieldId
|
|
429
|
+
},
|
|
430
|
+
testId: "table-column-settings-button"
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
getData: (el) => ({
|
|
434
|
+
type: "columnSettings",
|
|
435
|
+
fieldId: el.getAttribute("data-field-id")
|
|
436
|
+
})
|
|
707
437
|
};
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
438
|
+
var referencedCellButton = {
|
|
439
|
+
attr: BUTTON_IDENTIFIERS.referencedCell,
|
|
440
|
+
icon: "ph--link-simple-horizontal--regular",
|
|
441
|
+
render: ({ targetId, schemaId }) => {
|
|
442
|
+
return createButton({
|
|
443
|
+
attr: BUTTON_IDENTIFIERS.referencedCell,
|
|
444
|
+
icon: referencedCellButton.icon,
|
|
445
|
+
data: {
|
|
446
|
+
"data-target-id": targetId,
|
|
447
|
+
"data-schema-id": schemaId
|
|
448
|
+
},
|
|
449
|
+
testId: "table-ref-cell-button"
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
getData: (el) => ({
|
|
453
|
+
type: "referencedCell",
|
|
454
|
+
targetId: el.getAttribute("data-target-id"),
|
|
455
|
+
schemaId: el.getAttribute("data-schema-id")
|
|
456
|
+
})
|
|
720
457
|
};
|
|
721
|
-
var
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
458
|
+
var rowMenuButton = {
|
|
459
|
+
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
460
|
+
icon: "ph--dots-three--regular",
|
|
461
|
+
render: ({ rowIndex }) => {
|
|
462
|
+
return createButton({
|
|
463
|
+
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
464
|
+
icon: rowMenuButton.icon,
|
|
465
|
+
data: {
|
|
466
|
+
"data-row-index": rowIndex.toString()
|
|
467
|
+
},
|
|
468
|
+
testId: "table-row-menu-button"
|
|
469
|
+
});
|
|
470
|
+
},
|
|
471
|
+
getData: (el) => ({
|
|
472
|
+
type: "rowMenu",
|
|
473
|
+
rowIndex: Number(el.getAttribute("data-row-index"))
|
|
474
|
+
})
|
|
732
475
|
};
|
|
733
|
-
var
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
476
|
+
var sortButton = {
|
|
477
|
+
attr: BUTTON_IDENTIFIERS.sort,
|
|
478
|
+
icon: "ph--sort-ascending--regular",
|
|
479
|
+
render: ({ fieldId, direction }) => {
|
|
480
|
+
return createButton({
|
|
481
|
+
attr: BUTTON_IDENTIFIERS.sort,
|
|
482
|
+
icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
|
|
483
|
+
data: {
|
|
484
|
+
"data-field-id": fieldId,
|
|
485
|
+
"data-direction": direction ?? ""
|
|
486
|
+
},
|
|
487
|
+
testId: "table-sort-button",
|
|
488
|
+
// TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
|
|
489
|
+
// This is a bit hacky.
|
|
490
|
+
type: "secondary"
|
|
491
|
+
});
|
|
492
|
+
},
|
|
493
|
+
getData: (el) => ({
|
|
494
|
+
type: "sort",
|
|
495
|
+
fieldId: el.getAttribute("data-field-id"),
|
|
496
|
+
direction: el.getAttribute("data-direction")
|
|
497
|
+
})
|
|
744
498
|
};
|
|
745
|
-
var
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
499
|
+
var tableButtons = {
|
|
500
|
+
addColumn: addColumnButton,
|
|
501
|
+
columnSettings: columnSettingsButton,
|
|
502
|
+
referencedCell: referencedCellButton,
|
|
503
|
+
rowMenu: rowMenuButton,
|
|
504
|
+
sort: sortButton
|
|
750
505
|
};
|
|
751
506
|
|
|
752
|
-
// packages/ui/react-ui-table/src/
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
import { computed as computed2, effect as effect2, signal as signal3 } from "@preact/signals-core";
|
|
757
|
-
import orderBy from "lodash.orderby";
|
|
758
|
-
import { Resource as Resource2 } from "@dxos/context";
|
|
759
|
-
import { getValue as getValue2, setValue, FormatEnum as FormatEnum3 } from "@dxos/echo-schema";
|
|
760
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
761
|
-
import { PublicKey as PublicKey2 } from "@dxos/react-client";
|
|
762
|
-
import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay, formatForEditing, parseValue } from "@dxos/react-ui-form";
|
|
763
|
-
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
764
|
-
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
765
|
-
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
766
|
-
|
|
767
|
-
// packages/ui/react-ui-table/src/model/modal-controller.ts
|
|
768
|
-
import { signal } from "@preact/signals-core";
|
|
769
|
-
import { log as log2 } from "@dxos/log";
|
|
770
|
-
|
|
771
|
-
// packages/ui/react-ui-table/src/util/signals.ts
|
|
772
|
-
var touch = (value) => value;
|
|
773
|
-
|
|
774
|
-
// packages/ui/react-ui-table/src/util/table.ts
|
|
775
|
-
import { AST, Format, FormatEnum as FormatEnum2, S as S2, TypedObject, TypeEnum } from "@dxos/echo-schema";
|
|
776
|
-
import { log } from "@dxos/log";
|
|
777
|
-
import { PublicKey } from "@dxos/react-client";
|
|
778
|
-
import { create as create2 } from "@dxos/react-client/echo";
|
|
779
|
-
import { createFieldId, createView, ViewProjection } from "@dxos/schema";
|
|
780
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/util/table.ts";
|
|
781
|
-
var initializeTable = ({ space, table, initialRow = true }) => {
|
|
782
|
-
log.info("initializeTable", {
|
|
783
|
-
table
|
|
784
|
-
}, {
|
|
785
|
-
F: __dxlog_file3,
|
|
786
|
-
L: 32,
|
|
787
|
-
S: void 0,
|
|
788
|
-
C: (f, a) => f(...a)
|
|
789
|
-
});
|
|
790
|
-
const ContactSchema = TypedObject({
|
|
791
|
-
typename: `example.com/type/${PublicKey.random().truncate()}`,
|
|
792
|
-
version: "0.1.0"
|
|
793
|
-
})({
|
|
794
|
-
name: S2.optional(S2.String).annotations({
|
|
795
|
-
[AST.TitleAnnotationId]: "Name"
|
|
796
|
-
}),
|
|
797
|
-
email: S2.optional(Format.Email),
|
|
798
|
-
salary: S2.optional(Format.Currency()).annotations({
|
|
799
|
-
[AST.TitleAnnotationId]: "Salary"
|
|
800
|
-
})
|
|
801
|
-
});
|
|
802
|
-
const contactSchema = space.db.schemaRegistry.addSchema(ContactSchema);
|
|
803
|
-
table.view = createView({
|
|
804
|
-
name: "Test",
|
|
805
|
-
typename: contactSchema.typename,
|
|
806
|
-
jsonSchema: contactSchema.jsonSchema,
|
|
807
|
-
fields: [
|
|
808
|
-
"name",
|
|
809
|
-
"email",
|
|
810
|
-
"salary"
|
|
811
|
-
]
|
|
812
|
-
});
|
|
813
|
-
const projection = new ViewProjection(contactSchema, table.view);
|
|
814
|
-
projection.setFieldProjection({
|
|
815
|
-
field: {
|
|
816
|
-
id: table.view.fields[2].id,
|
|
817
|
-
path: "salary",
|
|
818
|
-
size: 150
|
|
819
|
-
}
|
|
820
|
-
});
|
|
821
|
-
projection.setFieldProjection({
|
|
822
|
-
field: {
|
|
823
|
-
id: createFieldId(),
|
|
824
|
-
path: "manager",
|
|
825
|
-
referencePath: "name"
|
|
826
|
-
},
|
|
827
|
-
props: {
|
|
828
|
-
property: "manager",
|
|
829
|
-
type: TypeEnum.Ref,
|
|
830
|
-
format: FormatEnum2.Ref,
|
|
831
|
-
referenceSchema: contactSchema.typename,
|
|
832
|
-
title: "Manager"
|
|
833
|
-
}
|
|
834
|
-
});
|
|
835
|
-
if (initialRow) {
|
|
836
|
-
space.db.add(create2(contactSchema, {}));
|
|
837
|
-
}
|
|
838
|
-
return contactSchema;
|
|
507
|
+
// packages/ui/react-ui-table/src/util/table-controls.ts
|
|
508
|
+
var CONTROL_IDENTIFIERS = {
|
|
509
|
+
checkbox: "data-table-checkbox",
|
|
510
|
+
switch: "data-table-switch"
|
|
839
511
|
};
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
referencedCell: "data-table-ref-cell-button",
|
|
844
|
-
columnSettings: "data-table-column-settings-button",
|
|
845
|
-
rowMenu: "data-table-row-menu-button",
|
|
846
|
-
newColumn: "data-table-new-column-button"
|
|
512
|
+
var BASE_CLASSES = {
|
|
513
|
+
checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] ch-checkbox",
|
|
514
|
+
switch: "absolute inset-block-[.25rem] inline-end-[.25rem] ch-checkbox--switch"
|
|
847
515
|
};
|
|
848
|
-
var
|
|
849
|
-
|
|
850
|
-
columnSettings: "ph--caret-down--regular",
|
|
851
|
-
rowMenu: "ph--dots-three--regular",
|
|
852
|
-
newColumn: "ph--plus--regular"
|
|
516
|
+
var renderAttributes = (data) => {
|
|
517
|
+
return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
853
518
|
};
|
|
854
|
-
var
|
|
855
|
-
|
|
856
|
-
return `<button class="${buttonClasses}" ${TABLE_ATTRS[button]}="${value}" data-testid="${testId}" ${disabled ? "disabled" : ""}><svg><use href="/icons.svg#${ICONS[button]}"/></svg></button>`;
|
|
519
|
+
var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
|
|
520
|
+
return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
|
|
857
521
|
};
|
|
858
|
-
var
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
attr:
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
522
|
+
var renderCheckbox = ({ rowIndex, header = false, checked = false, disabled = false }) => {
|
|
523
|
+
const attrs = {
|
|
524
|
+
[CONTROL_IDENTIFIERS.checkbox]: "",
|
|
525
|
+
"data-row-index": rowIndex.toString(),
|
|
526
|
+
...header && {
|
|
527
|
+
"data-header": ""
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
return renderInput(BASE_CLASSES.checkbox, attrs, checked, disabled, true, "table-selection");
|
|
531
|
+
};
|
|
532
|
+
var renderSwitch = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
|
|
533
|
+
const attrs = {
|
|
534
|
+
[CONTROL_IDENTIFIERS.switch]: "",
|
|
535
|
+
"data-row-index": rowIndex.toString(),
|
|
536
|
+
"data-col-index": colIndex.toString()
|
|
537
|
+
};
|
|
538
|
+
return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
|
|
539
|
+
};
|
|
540
|
+
var tableControls = {
|
|
541
|
+
checkbox: {
|
|
542
|
+
attr: CONTROL_IDENTIFIERS.checkbox,
|
|
543
|
+
render: renderCheckbox,
|
|
544
|
+
getData: (el) => ({
|
|
545
|
+
type: "checkbox",
|
|
546
|
+
rowIndex: Number(el.getAttribute("data-row-index")),
|
|
547
|
+
header: el.hasAttribute("data-header")
|
|
884
548
|
})
|
|
885
549
|
},
|
|
886
|
-
|
|
887
|
-
attr:
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
550
|
+
switch: {
|
|
551
|
+
attr: CONTROL_IDENTIFIERS.switch,
|
|
552
|
+
render: renderSwitch,
|
|
553
|
+
getData: (el) => ({
|
|
554
|
+
type: "switch",
|
|
555
|
+
rowIndex: Number(el.getAttribute("data-row-index")),
|
|
556
|
+
colIndex: Number(el.getAttribute("data-col-index"))
|
|
893
557
|
})
|
|
894
558
|
}
|
|
895
559
|
};
|
|
896
560
|
|
|
897
|
-
// packages/ui/react-ui-table/src/model/
|
|
898
|
-
var
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
this.
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
this.
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
const target = event.target;
|
|
909
|
-
const rowButton = target.closest(`button[${tableButtons.rowMenu.attr}]`);
|
|
910
|
-
if (rowButton) {
|
|
911
|
-
this._triggerRef.current = rowButton;
|
|
912
|
-
this._state.value = {
|
|
913
|
-
type: "row",
|
|
914
|
-
rowIndex: Number(rowButton.getAttribute(tableButtons.rowMenu.attr))
|
|
915
|
-
};
|
|
916
|
-
return true;
|
|
917
|
-
}
|
|
918
|
-
const columnButton = target.closest(`button[${tableButtons.columnSettings.attr}]`);
|
|
919
|
-
if (columnButton) {
|
|
920
|
-
const fieldId = columnButton.getAttribute(tableButtons.columnSettings.attr);
|
|
921
|
-
this._triggerRef.current = columnButton;
|
|
922
|
-
this._state.value = {
|
|
923
|
-
type: "column",
|
|
924
|
-
fieldId
|
|
925
|
-
};
|
|
926
|
-
return true;
|
|
927
|
-
}
|
|
928
|
-
const addColumnButton = target.closest(`button[${tableButtons.addColumn.attr}]`);
|
|
929
|
-
if (addColumnButton) {
|
|
930
|
-
this._triggerRef.current = addColumnButton;
|
|
931
|
-
this._state.value = {
|
|
932
|
-
type: "columnSettings",
|
|
933
|
-
mode: {
|
|
934
|
-
type: "create"
|
|
935
|
-
}
|
|
936
|
-
};
|
|
937
|
-
return true;
|
|
561
|
+
// packages/ui/react-ui-table/src/model/selection-model.ts
|
|
562
|
+
var SelectionModel = class extends Resource {
|
|
563
|
+
constructor(_rows, _onSelectionChanged) {
|
|
564
|
+
super();
|
|
565
|
+
this._rows = _rows;
|
|
566
|
+
this._onSelectionChanged = _onSelectionChanged;
|
|
567
|
+
this._selection = signal(/* @__PURE__ */ new Set());
|
|
568
|
+
this._validSelectedIds = computed(() => {
|
|
569
|
+
const rows = this._rows.value;
|
|
570
|
+
if (!rows) {
|
|
571
|
+
return /* @__PURE__ */ new Set();
|
|
938
572
|
}
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
this.
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
return false;
|
|
950
|
-
};
|
|
951
|
-
this.openColumnSettings = () => {
|
|
952
|
-
if (this._state.value.type === "column") {
|
|
953
|
-
const fieldId = this._state.value.fieldId;
|
|
954
|
-
requestAnimationFrame(() => {
|
|
955
|
-
this._state.value = {
|
|
956
|
-
type: "columnSettings",
|
|
957
|
-
mode: {
|
|
958
|
-
type: "edit",
|
|
959
|
-
fieldId
|
|
960
|
-
}
|
|
961
|
-
};
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
};
|
|
965
|
-
this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
|
|
966
|
-
if (anchorCell) {
|
|
967
|
-
this._triggerRef.current = anchorCell;
|
|
968
|
-
this._state.value = {
|
|
969
|
-
type: "createRefPanel",
|
|
970
|
-
typename,
|
|
971
|
-
initialValues,
|
|
972
|
-
onCreate
|
|
973
|
-
};
|
|
974
|
-
} else {
|
|
975
|
-
log2.warn("anchor cell not found while creating new ref", void 0, {
|
|
976
|
-
F: __dxlog_file4,
|
|
977
|
-
L: 119,
|
|
978
|
-
S: this,
|
|
979
|
-
C: (f, a) => f(...a)
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
};
|
|
983
|
-
this.close = () => {
|
|
984
|
-
this._state.value = {
|
|
985
|
-
type: "closed"
|
|
986
|
-
};
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
get state() {
|
|
990
|
-
return this._state;
|
|
991
|
-
}
|
|
992
|
-
get trigger() {
|
|
993
|
-
return this._triggerRef;
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
|
|
997
|
-
// packages/ui/react-ui-table/src/model/selection-model.ts
|
|
998
|
-
import { computed, effect, signal as signal2 } from "@preact/signals-core";
|
|
999
|
-
import { Resource } from "@dxos/context";
|
|
1000
|
-
var SelectionModel = class extends Resource {
|
|
1001
|
-
constructor(_rows, _onSelectionChanged) {
|
|
1002
|
-
super();
|
|
1003
|
-
this._rows = _rows;
|
|
1004
|
-
this._onSelectionChanged = _onSelectionChanged;
|
|
1005
|
-
this._selection = signal2(/* @__PURE__ */ new Set());
|
|
1006
|
-
this._validSelectedIds = computed(() => {
|
|
1007
|
-
const rows = this._rows.value;
|
|
1008
|
-
if (!rows) {
|
|
1009
|
-
return /* @__PURE__ */ new Set();
|
|
1010
|
-
}
|
|
1011
|
-
const validIds = new Set(rows.map((row) => row.id));
|
|
1012
|
-
return new Set([
|
|
1013
|
-
...this._selection.value
|
|
1014
|
-
].filter((id) => validIds.has(id)));
|
|
1015
|
-
});
|
|
1016
|
-
this._hasSelection = computed(() => this._validSelectedIds.value.size > 0);
|
|
1017
|
-
this._allSelected = computed(() => {
|
|
1018
|
-
const rows = this._rows.value;
|
|
1019
|
-
if (rows.length === 0) {
|
|
1020
|
-
return false;
|
|
573
|
+
const validIds = new Set(rows.map((row) => row.id));
|
|
574
|
+
return new Set([
|
|
575
|
+
...this._selection.value
|
|
576
|
+
].filter((id) => validIds.has(id)));
|
|
577
|
+
});
|
|
578
|
+
this._hasSelection = computed(() => this._validSelectedIds.value.size > 0);
|
|
579
|
+
this._allSelected = computed(() => {
|
|
580
|
+
const rows = this._rows.value;
|
|
581
|
+
if (rows.length === 0) {
|
|
582
|
+
return false;
|
|
1021
583
|
}
|
|
1022
584
|
return rows.every((row) => this._selection.value.has(row.id));
|
|
1023
585
|
});
|
|
@@ -1043,7 +605,16 @@ var SelectionModel = class extends Resource {
|
|
|
1043
605
|
this._selection.value = newSelection;
|
|
1044
606
|
};
|
|
1045
607
|
this.setSelection = (mode) => {
|
|
1046
|
-
|
|
608
|
+
switch (mode) {
|
|
609
|
+
case "all": {
|
|
610
|
+
this._selection.value = new Set(this._rows.value.map((row) => row.id));
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
case "none": {
|
|
614
|
+
this._selection.value = /* @__PURE__ */ new Set();
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
1047
618
|
};
|
|
1048
619
|
}
|
|
1049
620
|
async _open() {
|
|
@@ -1067,25 +638,165 @@ var SelectionModel = class extends Resource {
|
|
|
1067
638
|
}
|
|
1068
639
|
};
|
|
1069
640
|
|
|
1070
|
-
// packages/ui/react-ui-table/src/
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
};
|
|
1075
|
-
var
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
641
|
+
// packages/ui/react-ui-table/src/model/table-sorting.ts
|
|
642
|
+
import { computed as computed2, signal as signal2 } from "@preact/signals-core";
|
|
643
|
+
import orderBy from "lodash.orderby";
|
|
644
|
+
import { getValue, FormatEnum as FormatEnum2, TypeEnum as TypeEnum2 } from "@dxos/echo-schema";
|
|
645
|
+
import { formatForDisplay } from "@dxos/react-ui-form";
|
|
646
|
+
var TableSorting = class {
|
|
647
|
+
constructor(rows, _view, _projection) {
|
|
648
|
+
this._view = _view;
|
|
649
|
+
this._projection = _projection;
|
|
650
|
+
this._displayToDataIndex = /* @__PURE__ */ new Map();
|
|
651
|
+
this._localSort = signal2(void 0);
|
|
652
|
+
this._rows = rows;
|
|
653
|
+
this._isDirty = computed2(() => {
|
|
654
|
+
const local = this._localSort.value;
|
|
655
|
+
const viewSort = this._view?.query.sort?.[0];
|
|
656
|
+
if (local?.type === "cleared") {
|
|
657
|
+
return viewSort !== void 0;
|
|
658
|
+
}
|
|
659
|
+
if (local?.type === "active") {
|
|
660
|
+
if (!viewSort) {
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
|
|
664
|
+
}
|
|
665
|
+
return false;
|
|
666
|
+
});
|
|
667
|
+
this.sortedRows = this.initialiseSortedRows();
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* @reactive
|
|
671
|
+
* @returns Local sort if present, falls back to view sort.
|
|
672
|
+
*/
|
|
673
|
+
get sorting() {
|
|
674
|
+
const local = this._localSort.value;
|
|
675
|
+
if (local?.type === "cleared") {
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
if (local?.type === "active") {
|
|
679
|
+
return local.sort;
|
|
680
|
+
}
|
|
681
|
+
return this._view?.query.sort?.[0];
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* @reactive
|
|
685
|
+
* @returns Whether local sort differs from view sort.
|
|
686
|
+
*/
|
|
687
|
+
get isDirty() {
|
|
688
|
+
return this._isDirty.value;
|
|
689
|
+
}
|
|
690
|
+
getDataIndex(displayIndex) {
|
|
691
|
+
return this._displayToDataIndex.get(displayIndex) ?? displayIndex;
|
|
692
|
+
}
|
|
693
|
+
setSort(fieldId, direction) {
|
|
694
|
+
this._localSort.value = {
|
|
695
|
+
type: "active",
|
|
696
|
+
sort: {
|
|
697
|
+
fieldId,
|
|
698
|
+
direction
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
toggleSort(fieldId) {
|
|
703
|
+
if (!this._view || !this.sorting || this.sorting.fieldId !== fieldId) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
switch (this.sorting.direction) {
|
|
707
|
+
case "asc": {
|
|
708
|
+
this.setSort(fieldId, "desc");
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
case "desc": {
|
|
712
|
+
this.setSort(fieldId, "asc");
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
clearSort() {
|
|
718
|
+
this._localSort.value = {
|
|
719
|
+
type: "cleared"
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
save() {
|
|
723
|
+
if (this._view && this._localSort.value !== void 0) {
|
|
724
|
+
if (this._localSort.value.type === "active") {
|
|
725
|
+
this._view.query.sort = [
|
|
726
|
+
this._localSort.value.sort
|
|
727
|
+
];
|
|
728
|
+
} else {
|
|
729
|
+
this._view.query.sort = [];
|
|
730
|
+
}
|
|
731
|
+
this._localSort.value = void 0;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
//
|
|
735
|
+
// Initialisation.
|
|
736
|
+
//
|
|
737
|
+
initialiseSortedRows() {
|
|
738
|
+
return computed2(() => {
|
|
739
|
+
this._displayToDataIndex.clear();
|
|
740
|
+
const sort = this.sorting;
|
|
741
|
+
if (!sort || !this._view) {
|
|
742
|
+
return this._rows.value;
|
|
743
|
+
}
|
|
744
|
+
const field = this._view.fields.find((f) => f.id === sort.fieldId);
|
|
745
|
+
if (!field) {
|
|
746
|
+
return this._rows.value;
|
|
747
|
+
}
|
|
748
|
+
const { props } = this._projection.getFieldProjection(field.id);
|
|
749
|
+
const dataWithIndices = this._rows.value.map((item, index) => {
|
|
750
|
+
const sortValue = this.getSortValue(props, field, item);
|
|
751
|
+
const isEmpty = !(props.type === TypeEnum2.Boolean) && (sortValue == null || sortValue === "");
|
|
752
|
+
return {
|
|
753
|
+
item,
|
|
754
|
+
index,
|
|
755
|
+
value: sortValue,
|
|
756
|
+
isEmpty
|
|
757
|
+
};
|
|
758
|
+
});
|
|
759
|
+
const ordered = orderBy(dataWithIndices, [
|
|
760
|
+
"isEmpty",
|
|
761
|
+
"value"
|
|
762
|
+
], [
|
|
763
|
+
"asc",
|
|
764
|
+
sort.direction
|
|
765
|
+
]);
|
|
766
|
+
ordered.forEach(({ index: dataIndex }, displayIndex) => {
|
|
767
|
+
if (displayIndex !== dataIndex) {
|
|
768
|
+
this._displayToDataIndex.set(displayIndex, dataIndex);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
return ordered.map(({ item }) => item);
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
getSortValue(props, field, item) {
|
|
775
|
+
const { type, format } = props;
|
|
776
|
+
const value = getValue(item, field.path);
|
|
777
|
+
if (type === TypeEnum2.Boolean) {
|
|
778
|
+
return !!value;
|
|
779
|
+
}
|
|
780
|
+
if (type === TypeEnum2.Number) {
|
|
781
|
+
return value;
|
|
782
|
+
}
|
|
783
|
+
if (value == null) {
|
|
784
|
+
return value;
|
|
785
|
+
}
|
|
786
|
+
if (format === FormatEnum2.Ref && field.referencePath) {
|
|
787
|
+
const refValue = getValue(value.target, field.referencePath);
|
|
788
|
+
return refValue;
|
|
789
|
+
}
|
|
790
|
+
return formatForDisplay({
|
|
791
|
+
type,
|
|
792
|
+
format,
|
|
793
|
+
value
|
|
794
|
+
});
|
|
1084
795
|
}
|
|
1085
796
|
};
|
|
1086
797
|
|
|
1087
798
|
// packages/ui/react-ui-table/src/model/table-model.ts
|
|
1088
|
-
var
|
|
799
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/table-model.ts";
|
|
1089
800
|
var TableModel = class extends Resource2 {
|
|
1090
801
|
constructor({ table, projection, sorting = [], pinnedRows = {
|
|
1091
802
|
top: [],
|
|
@@ -1103,200 +814,7 @@ var TableModel = class extends Resource2 {
|
|
|
1103
814
|
col: 0
|
|
1104
815
|
}
|
|
1105
816
|
});
|
|
1106
|
-
/**
|
|
1107
|
-
* Maps display indices to data indices.
|
|
1108
|
-
* Used for translating between sorted/displayed order and original data order.
|
|
1109
|
-
* Keys are display indices, values are corresponding data indices.
|
|
1110
|
-
*/
|
|
1111
|
-
this._displayToDataIndex = /* @__PURE__ */ new Map();
|
|
1112
|
-
this._sorting = signal3(void 0);
|
|
1113
817
|
this._rows = signal3([]);
|
|
1114
|
-
this._modalController = new ModalController();
|
|
1115
|
-
//
|
|
1116
|
-
// Get Cells
|
|
1117
|
-
//
|
|
1118
|
-
this.getCells = (range, plane) => {
|
|
1119
|
-
switch (plane) {
|
|
1120
|
-
case "grid": {
|
|
1121
|
-
this._visibleRange.value = range;
|
|
1122
|
-
return this.getMainGridCells(range);
|
|
1123
|
-
}
|
|
1124
|
-
case "frozenRowsStart": {
|
|
1125
|
-
return this.getHeaderCells(range);
|
|
1126
|
-
}
|
|
1127
|
-
case "frozenColsStart": {
|
|
1128
|
-
return this.getSelectionColumnCells(range);
|
|
1129
|
-
}
|
|
1130
|
-
case "frozenColsEnd": {
|
|
1131
|
-
return this.getActionColumnCells(range);
|
|
1132
|
-
}
|
|
1133
|
-
case "fixedStartStart": {
|
|
1134
|
-
return this.getSelectAllCell();
|
|
1135
|
-
}
|
|
1136
|
-
case "fixedStartEnd": {
|
|
1137
|
-
return this.getNewColumnCell();
|
|
1138
|
-
}
|
|
1139
|
-
default: {
|
|
1140
|
-
return {};
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1144
|
-
this.getMainGridCells = (range) => {
|
|
1145
|
-
const cells = {};
|
|
1146
|
-
const fields = this._table.view?.fields ?? [];
|
|
1147
|
-
const addCell = (obj, field, colIndex, displayIndex) => {
|
|
1148
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
1149
|
-
const cell = {
|
|
1150
|
-
get value() {
|
|
1151
|
-
const value = getValue2(obj, field.path);
|
|
1152
|
-
if (value == null) {
|
|
1153
|
-
return "";
|
|
1154
|
-
}
|
|
1155
|
-
switch (props.format) {
|
|
1156
|
-
case FormatEnum3.Ref: {
|
|
1157
|
-
if (!field.referencePath) {
|
|
1158
|
-
return "";
|
|
1159
|
-
}
|
|
1160
|
-
return getValue2(value, field.referencePath);
|
|
1161
|
-
}
|
|
1162
|
-
default: {
|
|
1163
|
-
return formatForDisplay({
|
|
1164
|
-
type: props.type,
|
|
1165
|
-
format: props.format,
|
|
1166
|
-
value
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
};
|
|
1172
|
-
const classes = [];
|
|
1173
|
-
const formatClasses = cellClassesForFieldType({
|
|
1174
|
-
type: props.type,
|
|
1175
|
-
format: props.format
|
|
1176
|
-
});
|
|
1177
|
-
if (formatClasses) {
|
|
1178
|
-
classes.push(formatClasses);
|
|
1179
|
-
}
|
|
1180
|
-
const rowSelectionClasses = cellClassesForRowSelection(this._selection.isObjectSelected(obj));
|
|
1181
|
-
if (rowSelectionClasses) {
|
|
1182
|
-
classes.push(rowSelectionClasses);
|
|
1183
|
-
}
|
|
1184
|
-
if (classes.length > 0) {
|
|
1185
|
-
cell.className = mx2(classes.flat());
|
|
1186
|
-
}
|
|
1187
|
-
if (cell.value && props.format === FormatEnum3.Ref && props.referenceSchema) {
|
|
1188
|
-
const targetObj = getValue2(obj, field.path);
|
|
1189
|
-
cell.accessoryHtml = tableButtons.referencedCell.render({
|
|
1190
|
-
targetId: targetObj.id,
|
|
1191
|
-
schemaId: props.referenceSchema
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
|
-
const idx = toPlaneCellIndex({
|
|
1195
|
-
col: colIndex,
|
|
1196
|
-
row: displayIndex
|
|
1197
|
-
});
|
|
1198
|
-
cells[idx] = cell;
|
|
1199
|
-
};
|
|
1200
|
-
for (let row = range.start.row; row <= range.end.row && row < this._sortedRows.value.length; row++) {
|
|
1201
|
-
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1202
|
-
const field = fields[col];
|
|
1203
|
-
if (!field) {
|
|
1204
|
-
continue;
|
|
1205
|
-
}
|
|
1206
|
-
addCell(this._sortedRows.value[row], field, col, row);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
return cells;
|
|
1210
|
-
};
|
|
1211
|
-
this.getHeaderCells = (range) => {
|
|
1212
|
-
const cells = {};
|
|
1213
|
-
const fields = this.table.view?.fields ?? [];
|
|
1214
|
-
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1215
|
-
const { field, props } = this._projection.getFieldProjection(fields[col].id);
|
|
1216
|
-
cells[toPlaneCellIndex({
|
|
1217
|
-
col,
|
|
1218
|
-
row: 0
|
|
1219
|
-
})] = {
|
|
1220
|
-
// TODO(burdon): Use same logic as form for fallback title.
|
|
1221
|
-
value: props.title ?? field.path,
|
|
1222
|
-
readonly: true,
|
|
1223
|
-
resizeHandle: "col",
|
|
1224
|
-
accessoryHtml: tableButtons.columnSettings.render({
|
|
1225
|
-
fieldId: field.id
|
|
1226
|
-
})
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
return cells;
|
|
1230
|
-
};
|
|
1231
|
-
this.getSelectionColumnCells = (range) => {
|
|
1232
|
-
const cells = {};
|
|
1233
|
-
for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
|
|
1234
|
-
const isSelected = this._selection.isRowIndexSelected(row);
|
|
1235
|
-
const classes = cellClassesForRowSelection(isSelected);
|
|
1236
|
-
cells[toPlaneCellIndex({
|
|
1237
|
-
col: 0,
|
|
1238
|
-
row
|
|
1239
|
-
})] = {
|
|
1240
|
-
value: "",
|
|
1241
|
-
readonly: true,
|
|
1242
|
-
className: classes ? mx2(classes) : void 0,
|
|
1243
|
-
accessoryHtml: tableControls.checkbox.render({
|
|
1244
|
-
rowIndex: row,
|
|
1245
|
-
checked: isSelected
|
|
1246
|
-
})
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
return cells;
|
|
1250
|
-
};
|
|
1251
|
-
this.getActionColumnCells = (range) => {
|
|
1252
|
-
const cells = {};
|
|
1253
|
-
for (let row = range.start.row; row <= range.end.row && row < this._rows.value.length; row++) {
|
|
1254
|
-
const isSelected = this._selection.isRowIndexSelected(row);
|
|
1255
|
-
const classes = cellClassesForRowSelection(isSelected);
|
|
1256
|
-
cells[toPlaneCellIndex({
|
|
1257
|
-
col: 0,
|
|
1258
|
-
row
|
|
1259
|
-
})] = {
|
|
1260
|
-
value: "",
|
|
1261
|
-
readonly: true,
|
|
1262
|
-
className: classes ? mx2(classes) : void 0,
|
|
1263
|
-
accessoryHtml: tableButtons.rowMenu.render({
|
|
1264
|
-
rowIndex: row
|
|
1265
|
-
})
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
return cells;
|
|
1269
|
-
};
|
|
1270
|
-
this.getSelectAllCell = () => {
|
|
1271
|
-
return {
|
|
1272
|
-
[toPlaneCellIndex({
|
|
1273
|
-
col: 0,
|
|
1274
|
-
row: 0
|
|
1275
|
-
})]: {
|
|
1276
|
-
value: "",
|
|
1277
|
-
accessoryHtml: tableControls.checkbox.render({
|
|
1278
|
-
rowIndex: 0,
|
|
1279
|
-
header: true,
|
|
1280
|
-
checked: this._selection.allRowsSeleted.value
|
|
1281
|
-
}),
|
|
1282
|
-
readonly: true
|
|
1283
|
-
}
|
|
1284
|
-
};
|
|
1285
|
-
};
|
|
1286
|
-
this.getNewColumnCell = () => {
|
|
1287
|
-
return {
|
|
1288
|
-
[toPlaneCellIndex({
|
|
1289
|
-
col: 0,
|
|
1290
|
-
row: 0
|
|
1291
|
-
})]: {
|
|
1292
|
-
value: "",
|
|
1293
|
-
accessoryHtml: tableButtons.addColumn.render({
|
|
1294
|
-
disabled: (this._table.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1295
|
-
}),
|
|
1296
|
-
readonly: true
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
|
-
};
|
|
1300
818
|
//
|
|
1301
819
|
// Data
|
|
1302
820
|
//
|
|
@@ -1304,13 +822,13 @@ var TableModel = class extends Resource2 {
|
|
|
1304
822
|
this._rows.value = obj;
|
|
1305
823
|
};
|
|
1306
824
|
this.getRowCount = () => this._rows.value.length;
|
|
1307
|
-
this.getColumnCount = () => this.table.view?.fields.length ?? 0;
|
|
825
|
+
this.getColumnCount = () => this.table.view?.target?.fields.length ?? 0;
|
|
1308
826
|
this.insertRow = (rowIndex) => {
|
|
1309
|
-
const row = rowIndex !== void 0 ? this.
|
|
827
|
+
const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
|
|
1310
828
|
this._onInsertRow?.(row);
|
|
1311
829
|
};
|
|
1312
830
|
this.deleteRow = (rowIndex) => {
|
|
1313
|
-
const row = this.
|
|
831
|
+
const row = this._sorting.getDataIndex(rowIndex);
|
|
1314
832
|
const obj = this._rows.value[row];
|
|
1315
833
|
const objectsToDelete = [];
|
|
1316
834
|
if (this._selection.hasSelection.value) {
|
|
@@ -1322,12 +840,12 @@ var TableModel = class extends Resource2 {
|
|
|
1322
840
|
this._onDeleteRows?.(row, objectsToDelete);
|
|
1323
841
|
};
|
|
1324
842
|
this.getCellData = ({ col, row }) => {
|
|
1325
|
-
const fields = this.table.view?.fields ?? [];
|
|
843
|
+
const fields = this.table.view?.target?.fields ?? [];
|
|
1326
844
|
if (col < 0 || col >= fields.length) {
|
|
1327
845
|
return void 0;
|
|
1328
846
|
}
|
|
1329
847
|
const field = fields[col];
|
|
1330
|
-
const dataIndex = this.
|
|
848
|
+
const dataIndex = this._sorting.getDataIndex(row);
|
|
1331
849
|
const value = getValue2(this._rows.value[dataIndex], field.path);
|
|
1332
850
|
if (value == null) {
|
|
1333
851
|
return "";
|
|
@@ -1338,7 +856,7 @@ var TableModel = class extends Resource2 {
|
|
|
1338
856
|
if (!field.referencePath) {
|
|
1339
857
|
return "";
|
|
1340
858
|
}
|
|
1341
|
-
return getValue2(value, field.referencePath);
|
|
859
|
+
return getValue2(value.target, field.referencePath);
|
|
1342
860
|
}
|
|
1343
861
|
default: {
|
|
1344
862
|
return formatForEditing({
|
|
@@ -1350,8 +868,8 @@ var TableModel = class extends Resource2 {
|
|
|
1350
868
|
}
|
|
1351
869
|
};
|
|
1352
870
|
this.setCellData = ({ col, row }, value) => {
|
|
1353
|
-
const rowIdx = this.
|
|
1354
|
-
const fields = this.table.view?.fields ?? [];
|
|
871
|
+
const rowIdx = this._sorting.getDataIndex(row);
|
|
872
|
+
const fields = this.table.view?.target?.fields ?? [];
|
|
1355
873
|
if (col < 0 || col >= fields.length) {
|
|
1356
874
|
return;
|
|
1357
875
|
}
|
|
@@ -1359,7 +877,9 @@ var TableModel = class extends Resource2 {
|
|
|
1359
877
|
const { props } = this._projection.getFieldProjection(field.id);
|
|
1360
878
|
switch (props.format) {
|
|
1361
879
|
case FormatEnum3.Ref: {
|
|
1362
|
-
|
|
880
|
+
if (isReactiveObject(value)) {
|
|
881
|
+
setValue(this._rows.value[rowIdx], field.path, makeRef2(value));
|
|
882
|
+
}
|
|
1363
883
|
break;
|
|
1364
884
|
}
|
|
1365
885
|
default: {
|
|
@@ -1372,31 +892,13 @@ var TableModel = class extends Resource2 {
|
|
|
1372
892
|
}
|
|
1373
893
|
}
|
|
1374
894
|
};
|
|
1375
|
-
//
|
|
1376
|
-
// Interactions
|
|
1377
|
-
//
|
|
1378
|
-
this.handleGridClick = (event) => {
|
|
1379
|
-
if (!this._modalController.handleClick(event)) {
|
|
1380
|
-
const target = event.target;
|
|
1381
|
-
const selectionCheckbox = target.closest(`input[${tableControls.checkbox.attributes.checkbox}]`);
|
|
1382
|
-
if (selectionCheckbox) {
|
|
1383
|
-
const isHeader = selectionCheckbox.hasAttribute(tableControls.checkbox.attributes.header);
|
|
1384
|
-
if (isHeader) {
|
|
1385
|
-
if (this._selection.allRowsSeleted.value) {
|
|
1386
|
-
this._selection.setSelection("none");
|
|
1387
|
-
} else {
|
|
1388
|
-
this._selection.setSelection("all");
|
|
1389
|
-
}
|
|
1390
|
-
} else {
|
|
1391
|
-
const rowIndex = Number(selectionCheckbox.getAttribute(tableControls.checkbox.attributes.checkbox));
|
|
1392
|
-
this._selection.toggleSelectionForRowIndex(rowIndex);
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
};
|
|
1397
895
|
this._table = table;
|
|
1398
896
|
this._projection = projection;
|
|
1399
|
-
this._sorting
|
|
897
|
+
this._sorting = new TableSorting(this._rows, table.view?.target, projection);
|
|
898
|
+
if (sorting.length > 0) {
|
|
899
|
+
const [sort] = sorting;
|
|
900
|
+
this._sorting.setSort(sort.fieldId, sort.direction);
|
|
901
|
+
}
|
|
1400
902
|
this._pinnedRows = pinnedRows;
|
|
1401
903
|
this._onInsertRow = onInsertRow;
|
|
1402
904
|
this._onDeleteRows = onDeleteRows;
|
|
@@ -1410,13 +912,22 @@ var TableModel = class extends Resource2 {
|
|
|
1410
912
|
get projection() {
|
|
1411
913
|
return this._projection;
|
|
1412
914
|
}
|
|
915
|
+
get rows() {
|
|
916
|
+
return this._sorting.sortedRows;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* @reactive
|
|
920
|
+
*/
|
|
921
|
+
get sorting() {
|
|
922
|
+
return this._sorting;
|
|
923
|
+
}
|
|
1413
924
|
get pinnedRows() {
|
|
1414
925
|
return this._pinnedRows;
|
|
1415
926
|
}
|
|
1416
927
|
get columnMeta() {
|
|
1417
|
-
|
|
1418
|
-
F:
|
|
1419
|
-
L:
|
|
928
|
+
invariant(this._columnMeta, void 0, {
|
|
929
|
+
F: __dxlog_file,
|
|
930
|
+
L: 117,
|
|
1420
931
|
S: this,
|
|
1421
932
|
A: [
|
|
1422
933
|
"this._columnMeta",
|
|
@@ -1425,28 +936,25 @@ var TableModel = class extends Resource2 {
|
|
|
1425
936
|
});
|
|
1426
937
|
return this._columnMeta;
|
|
1427
938
|
}
|
|
1428
|
-
get sorting() {
|
|
1429
|
-
return this._sorting.value;
|
|
1430
|
-
}
|
|
1431
|
-
get modalController() {
|
|
1432
|
-
return this._modalController;
|
|
1433
|
-
}
|
|
1434
939
|
get selection() {
|
|
1435
940
|
return this._selection;
|
|
1436
941
|
}
|
|
942
|
+
/** @reactive */
|
|
943
|
+
get isViewDirty() {
|
|
944
|
+
return this._sorting.isDirty;
|
|
945
|
+
}
|
|
1437
946
|
//
|
|
1438
947
|
// Initialisation
|
|
1439
948
|
//
|
|
1440
949
|
async _open() {
|
|
1441
950
|
this.initializeColumnMeta();
|
|
1442
|
-
this.initializeSorting();
|
|
1443
951
|
this.initializeEffects();
|
|
1444
|
-
this._selection = new SelectionModel(this.
|
|
952
|
+
this._selection = new SelectionModel(this._sorting.sortedRows, () => this._onRowOrderChanged?.());
|
|
1445
953
|
await this._selection.open(this._ctx);
|
|
1446
954
|
}
|
|
1447
955
|
initializeColumnMeta() {
|
|
1448
|
-
this._columnMeta =
|
|
1449
|
-
const fields = this._table.view?.fields ?? [];
|
|
956
|
+
this._columnMeta = computed3(() => {
|
|
957
|
+
const fields = this._table.view?.target?.fields ?? [];
|
|
1450
958
|
const meta = Object.fromEntries(fields.map((field, index) => [
|
|
1451
959
|
index,
|
|
1452
960
|
{
|
|
@@ -1471,45 +979,9 @@ var TableModel = class extends Resource2 {
|
|
|
1471
979
|
};
|
|
1472
980
|
});
|
|
1473
981
|
}
|
|
1474
|
-
initializeSorting() {
|
|
1475
|
-
this._sortedRows = computed2(() => {
|
|
1476
|
-
this._displayToDataIndex.clear();
|
|
1477
|
-
const sort = this._sorting.value;
|
|
1478
|
-
if (!sort) {
|
|
1479
|
-
return this._rows.value;
|
|
1480
|
-
}
|
|
1481
|
-
const field = this._table.view?.fields.find((field2) => field2.id === sort.fieldId);
|
|
1482
|
-
if (!field) {
|
|
1483
|
-
return this._rows.value;
|
|
1484
|
-
}
|
|
1485
|
-
const dataWithIndices = this._rows.value.map((item, index) => {
|
|
1486
|
-
const value = getValue2(item, field.path);
|
|
1487
|
-
return {
|
|
1488
|
-
item,
|
|
1489
|
-
index,
|
|
1490
|
-
value,
|
|
1491
|
-
isEmpty: value == null || value === ""
|
|
1492
|
-
};
|
|
1493
|
-
});
|
|
1494
|
-
const sorted = orderBy(dataWithIndices, [
|
|
1495
|
-
"isEmpty",
|
|
1496
|
-
"value"
|
|
1497
|
-
], [
|
|
1498
|
-
"asc",
|
|
1499
|
-
sort.direction
|
|
1500
|
-
]);
|
|
1501
|
-
for (let displayIndex = 0; displayIndex < sorted.length; displayIndex++) {
|
|
1502
|
-
const { index: dataIndex } = sorted[displayIndex];
|
|
1503
|
-
if (displayIndex !== dataIndex) {
|
|
1504
|
-
this._displayToDataIndex.set(displayIndex, dataIndex);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
return sorted.map(({ item }) => item);
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
982
|
initializeEffects() {
|
|
1511
983
|
const rowOrderWatcher = effect2(() => {
|
|
1512
|
-
touch(this.
|
|
984
|
+
touch(this._sorting.sortedRows.value);
|
|
1513
985
|
this._onRowOrderChanged?.();
|
|
1514
986
|
});
|
|
1515
987
|
this._ctx.onDispose(rowOrderWatcher);
|
|
@@ -1518,8 +990,8 @@ var TableModel = class extends Resource2 {
|
|
|
1518
990
|
const rowEffects = [];
|
|
1519
991
|
for (let row = start.row; row <= end.row; row++) {
|
|
1520
992
|
rowEffects.push(effect2(() => {
|
|
1521
|
-
const obj = this.
|
|
1522
|
-
this?._table?.view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
|
|
993
|
+
const obj = this._sorting.sortedRows.value[row];
|
|
994
|
+
this?._table?.view?.target?.fields.forEach((field) => touch(getValue2(obj, field.path)));
|
|
1523
995
|
this._onCellUpdate?.({
|
|
1524
996
|
row,
|
|
1525
997
|
col: start.col,
|
|
@@ -1531,6 +1003,19 @@ var TableModel = class extends Resource2 {
|
|
|
1531
1003
|
});
|
|
1532
1004
|
this._ctx.onDispose(rowEffectManager);
|
|
1533
1005
|
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Updates a cell's value using a transform function.
|
|
1008
|
+
* @param {DxGridPlanePosition} position - The position of the cell to update.
|
|
1009
|
+
* @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
|
|
1010
|
+
*/
|
|
1011
|
+
updateCellData({ col, row }, update) {
|
|
1012
|
+
const dataRow = this._sorting.getDataIndex(row);
|
|
1013
|
+
const fields = this.table.view?.target?.fields ?? [];
|
|
1014
|
+
const field = fields[col];
|
|
1015
|
+
const value = getValue2(this._rows.value[dataRow], field.path);
|
|
1016
|
+
const updatedValue = update(value);
|
|
1017
|
+
setValue(this._rows.value[dataRow], field.path, updatedValue);
|
|
1018
|
+
}
|
|
1534
1019
|
//
|
|
1535
1020
|
// Column Operations
|
|
1536
1021
|
//
|
|
@@ -1538,11 +1023,8 @@ var TableModel = class extends Resource2 {
|
|
|
1538
1023
|
if (!this.table.view) {
|
|
1539
1024
|
return;
|
|
1540
1025
|
}
|
|
1541
|
-
const field = this.table.view.fields.find((field2) => field2.id === fieldId);
|
|
1026
|
+
const field = this.table.view.target?.fields.find((field2) => field2.id === fieldId);
|
|
1542
1027
|
if (field && this._onDeleteColumn) {
|
|
1543
|
-
if (this._sorting.value?.fieldId === fieldId) {
|
|
1544
|
-
this.clearSort();
|
|
1545
|
-
}
|
|
1546
1028
|
this._onDeleteColumn(field.id);
|
|
1547
1029
|
}
|
|
1548
1030
|
}
|
|
@@ -1550,7 +1032,7 @@ var TableModel = class extends Resource2 {
|
|
|
1550
1032
|
// Resize
|
|
1551
1033
|
//
|
|
1552
1034
|
setColumnWidth(columnIndex, width) {
|
|
1553
|
-
const fields = this.table.view?.fields ?? [];
|
|
1035
|
+
const fields = this.table.view?.target?.fields ?? [];
|
|
1554
1036
|
if (columnIndex < fields.length) {
|
|
1555
1037
|
const newWidth = Math.max(0, width);
|
|
1556
1038
|
const field = fields[columnIndex];
|
|
@@ -1560,18 +1042,6 @@ var TableModel = class extends Resource2 {
|
|
|
1560
1042
|
}
|
|
1561
1043
|
}
|
|
1562
1044
|
//
|
|
1563
|
-
// Sorting
|
|
1564
|
-
//
|
|
1565
|
-
setSort(fieldId, direction) {
|
|
1566
|
-
this._sorting.value = {
|
|
1567
|
-
fieldId,
|
|
1568
|
-
direction
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
clearSort() {
|
|
1572
|
-
this._sorting.value = void 0;
|
|
1573
|
-
}
|
|
1574
|
-
//
|
|
1575
1045
|
// Pinning
|
|
1576
1046
|
//
|
|
1577
1047
|
// TODO(burdon): Change to setPinned(on/off).
|
|
@@ -1582,9 +1052,870 @@ var TableModel = class extends Resource2 {
|
|
|
1582
1052
|
this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
|
|
1583
1053
|
this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
|
|
1584
1054
|
}
|
|
1055
|
+
//
|
|
1056
|
+
// View operations
|
|
1057
|
+
//
|
|
1058
|
+
saveView() {
|
|
1059
|
+
this._sorting.save();
|
|
1060
|
+
}
|
|
1585
1061
|
};
|
|
1586
1062
|
|
|
1587
|
-
// packages/ui/react-ui-table/src/
|
|
1063
|
+
// packages/ui/react-ui-table/src/model/modal-controller.ts
|
|
1064
|
+
import { signal as signal4 } from "@preact/signals-core";
|
|
1065
|
+
import { log } from "@dxos/log";
|
|
1066
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
|
|
1067
|
+
var ModalController = class {
|
|
1068
|
+
constructor() {
|
|
1069
|
+
this._state = signal4({
|
|
1070
|
+
type: "closed"
|
|
1071
|
+
});
|
|
1072
|
+
this._triggerRef = {
|
|
1073
|
+
current: null
|
|
1074
|
+
};
|
|
1075
|
+
this.setTrigger = (trigger) => {
|
|
1076
|
+
this._triggerRef.current = trigger;
|
|
1077
|
+
};
|
|
1078
|
+
this.showRowMenu = (rowIndex) => {
|
|
1079
|
+
this._state.value = {
|
|
1080
|
+
type: "row",
|
|
1081
|
+
rowIndex
|
|
1082
|
+
};
|
|
1083
|
+
};
|
|
1084
|
+
this.showColumnMenu = (fieldId) => {
|
|
1085
|
+
this._state.value = {
|
|
1086
|
+
type: "column",
|
|
1087
|
+
fieldId
|
|
1088
|
+
};
|
|
1089
|
+
};
|
|
1090
|
+
this.showColumnCreator = () => {
|
|
1091
|
+
this._state.value = {
|
|
1092
|
+
type: "columnSettings",
|
|
1093
|
+
mode: {
|
|
1094
|
+
type: "create"
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
this.showReferencePanel = (targetId, schemaId) => {
|
|
1099
|
+
this._state.value = {
|
|
1100
|
+
type: "refPanel",
|
|
1101
|
+
targetId,
|
|
1102
|
+
typename: schemaId
|
|
1103
|
+
};
|
|
1104
|
+
};
|
|
1105
|
+
this.openColumnSettings = () => {
|
|
1106
|
+
if (this._state.value.type === "column") {
|
|
1107
|
+
const fieldId = this._state.value.fieldId;
|
|
1108
|
+
requestAnimationFrame(() => {
|
|
1109
|
+
this._state.value = {
|
|
1110
|
+
type: "columnSettings",
|
|
1111
|
+
mode: {
|
|
1112
|
+
type: "edit",
|
|
1113
|
+
fieldId
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
|
|
1120
|
+
if (anchorCell) {
|
|
1121
|
+
this._triggerRef.current = anchorCell;
|
|
1122
|
+
this._state.value = {
|
|
1123
|
+
type: "createRefPanel",
|
|
1124
|
+
typename,
|
|
1125
|
+
initialValues,
|
|
1126
|
+
onCreate
|
|
1127
|
+
};
|
|
1128
|
+
} else {
|
|
1129
|
+
log.warn("anchor cell not found while creating new ref", void 0, {
|
|
1130
|
+
F: __dxlog_file2,
|
|
1131
|
+
L: 86,
|
|
1132
|
+
S: this,
|
|
1133
|
+
C: (f, a) => f(...a)
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
this.close = () => {
|
|
1138
|
+
this._state.value = {
|
|
1139
|
+
type: "closed"
|
|
1140
|
+
};
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
get state() {
|
|
1144
|
+
return this._state;
|
|
1145
|
+
}
|
|
1146
|
+
get trigger() {
|
|
1147
|
+
return this._triggerRef;
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
// packages/ui/react-ui-table/src/model/table-presentation.ts
|
|
1152
|
+
import { signal as signal5 } from "@preact/signals-core";
|
|
1153
|
+
import { FormatEnum as FormatEnum4, getValue as getValue3 } from "@dxos/echo-schema";
|
|
1154
|
+
import { cellClassesForFieldType, cellClassesForRowSelection, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
|
|
1155
|
+
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
1156
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
1157
|
+
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1158
|
+
var TablePresentation = class {
|
|
1159
|
+
constructor(model, _visibleRange = signal5({
|
|
1160
|
+
start: {
|
|
1161
|
+
row: 0,
|
|
1162
|
+
col: 0
|
|
1163
|
+
},
|
|
1164
|
+
end: {
|
|
1165
|
+
row: 0,
|
|
1166
|
+
col: 0
|
|
1167
|
+
}
|
|
1168
|
+
})) {
|
|
1169
|
+
this.model = model;
|
|
1170
|
+
this._visibleRange = _visibleRange;
|
|
1171
|
+
}
|
|
1172
|
+
getCells(range, plane) {
|
|
1173
|
+
switch (plane) {
|
|
1174
|
+
case "grid":
|
|
1175
|
+
this._visibleRange.value = range;
|
|
1176
|
+
return this.getMainGridCells(range);
|
|
1177
|
+
case "frozenRowsStart":
|
|
1178
|
+
return this.getHeaderCells(range);
|
|
1179
|
+
case "frozenColsStart":
|
|
1180
|
+
return this.getSelectionColumnCells(range);
|
|
1181
|
+
case "frozenColsEnd":
|
|
1182
|
+
return this.getActionColumnCells(range);
|
|
1183
|
+
case "fixedStartStart":
|
|
1184
|
+
return this.getSelectAllCell();
|
|
1185
|
+
case "fixedStartEnd":
|
|
1186
|
+
return this.getNewColumnCell();
|
|
1187
|
+
default:
|
|
1188
|
+
return {};
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
getMainGridCells(range) {
|
|
1192
|
+
const cells = {};
|
|
1193
|
+
const fields = this.model.table.view?.target?.fields ?? [];
|
|
1194
|
+
const addCell = (obj, field, colIndex, displayIndex) => {
|
|
1195
|
+
const { props } = this.model.projection.getFieldProjection(field.id);
|
|
1196
|
+
const cell = {
|
|
1197
|
+
get value() {
|
|
1198
|
+
const value = getValue3(obj, field.path);
|
|
1199
|
+
if (value == null) {
|
|
1200
|
+
return "";
|
|
1201
|
+
}
|
|
1202
|
+
switch (props.format) {
|
|
1203
|
+
case FormatEnum4.Boolean: {
|
|
1204
|
+
return "";
|
|
1205
|
+
}
|
|
1206
|
+
case FormatEnum4.Ref: {
|
|
1207
|
+
if (!field.referencePath) {
|
|
1208
|
+
return "";
|
|
1209
|
+
}
|
|
1210
|
+
return getValue3(value.target, field.referencePath);
|
|
1211
|
+
}
|
|
1212
|
+
default: {
|
|
1213
|
+
return formatForDisplay2({
|
|
1214
|
+
type: props.type,
|
|
1215
|
+
format: props.format,
|
|
1216
|
+
value
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
const classes = [];
|
|
1223
|
+
const formatClasses = cellClassesForFieldType({
|
|
1224
|
+
type: props.type,
|
|
1225
|
+
format: props.format
|
|
1226
|
+
});
|
|
1227
|
+
if (formatClasses) {
|
|
1228
|
+
classes.push(formatClasses);
|
|
1229
|
+
}
|
|
1230
|
+
const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj));
|
|
1231
|
+
if (rowSelectionClasses) {
|
|
1232
|
+
classes.push(rowSelectionClasses);
|
|
1233
|
+
}
|
|
1234
|
+
if (classes.length > 0) {
|
|
1235
|
+
cell.className = mx(classes.flat());
|
|
1236
|
+
}
|
|
1237
|
+
if (props.format === FormatEnum4.Ref && props.referenceSchema) {
|
|
1238
|
+
const targetObj = getValue3(obj, field.path)?.target;
|
|
1239
|
+
if (targetObj) {
|
|
1240
|
+
cell.accessoryHtml = tableButtons.referencedCell.render({
|
|
1241
|
+
targetId: targetObj.id,
|
|
1242
|
+
schemaId: props.referenceSchema
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (props.format === FormatEnum4.Boolean) {
|
|
1247
|
+
const value = getValue3(obj, field.path);
|
|
1248
|
+
cell.accessoryHtml = tableControls.switch.render({
|
|
1249
|
+
colIndex,
|
|
1250
|
+
rowIndex: displayIndex,
|
|
1251
|
+
checked: value ?? false
|
|
1252
|
+
});
|
|
1253
|
+
cell.readonly = true;
|
|
1254
|
+
}
|
|
1255
|
+
const idx = toPlaneCellIndex({
|
|
1256
|
+
col: colIndex,
|
|
1257
|
+
row: displayIndex
|
|
1258
|
+
});
|
|
1259
|
+
cells[idx] = cell;
|
|
1260
|
+
};
|
|
1261
|
+
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1262
|
+
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1263
|
+
const field = fields[col];
|
|
1264
|
+
if (!field) {
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
addCell(this.model.rows.value[row], field, col, row);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return cells;
|
|
1271
|
+
}
|
|
1272
|
+
getHeaderCells(range) {
|
|
1273
|
+
const cells = {};
|
|
1274
|
+
const fields = this.model.table.view?.target?.fields ?? [];
|
|
1275
|
+
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1276
|
+
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
1277
|
+
const sorting = this.model.sorting?.sorting;
|
|
1278
|
+
const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
|
|
1279
|
+
cells[toPlaneCellIndex({
|
|
1280
|
+
col,
|
|
1281
|
+
row: 0
|
|
1282
|
+
})] = {
|
|
1283
|
+
// TODO(burdon): Use same logic as form for fallback title.
|
|
1284
|
+
value: props.title ?? field.path,
|
|
1285
|
+
readonly: true,
|
|
1286
|
+
resizeHandle: "col",
|
|
1287
|
+
accessoryHtml: `
|
|
1288
|
+
${direction !== void 0 ? tableButtons.sort.render({
|
|
1289
|
+
fieldId: field.id,
|
|
1290
|
+
direction
|
|
1291
|
+
}) : ""}
|
|
1292
|
+
${tableButtons.columnSettings.render({
|
|
1293
|
+
fieldId: field.id
|
|
1294
|
+
})}
|
|
1295
|
+
`,
|
|
1296
|
+
className: "!bg-gridHeader"
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
return cells;
|
|
1300
|
+
}
|
|
1301
|
+
getSelectionColumnCells(range) {
|
|
1302
|
+
const cells = {};
|
|
1303
|
+
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1304
|
+
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
1305
|
+
const classes = cellClassesForRowSelection(isSelected);
|
|
1306
|
+
cells[toPlaneCellIndex({
|
|
1307
|
+
col: 0,
|
|
1308
|
+
row
|
|
1309
|
+
})] = {
|
|
1310
|
+
value: "",
|
|
1311
|
+
readonly: true,
|
|
1312
|
+
className: classes ? mx(classes) : void 0,
|
|
1313
|
+
accessoryHtml: tableControls.checkbox.render({
|
|
1314
|
+
rowIndex: row,
|
|
1315
|
+
checked: isSelected
|
|
1316
|
+
})
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
return cells;
|
|
1320
|
+
}
|
|
1321
|
+
getActionColumnCells(range) {
|
|
1322
|
+
const cells = {};
|
|
1323
|
+
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1324
|
+
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
1325
|
+
const classes = cellClassesForRowSelection(isSelected);
|
|
1326
|
+
cells[toPlaneCellIndex({
|
|
1327
|
+
col: 0,
|
|
1328
|
+
row
|
|
1329
|
+
})] = {
|
|
1330
|
+
value: "",
|
|
1331
|
+
readonly: true,
|
|
1332
|
+
className: classes ? mx(classes) : void 0,
|
|
1333
|
+
accessoryHtml: tableButtons.rowMenu.render({
|
|
1334
|
+
rowIndex: row
|
|
1335
|
+
})
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
return cells;
|
|
1339
|
+
}
|
|
1340
|
+
getSelectAllCell() {
|
|
1341
|
+
return {
|
|
1342
|
+
[toPlaneCellIndex({
|
|
1343
|
+
col: 0,
|
|
1344
|
+
row: 0
|
|
1345
|
+
})]: {
|
|
1346
|
+
accessoryHtml: tableControls.checkbox.render({
|
|
1347
|
+
rowIndex: 0,
|
|
1348
|
+
header: true,
|
|
1349
|
+
checked: this.model.selection.allRowsSeleted.value
|
|
1350
|
+
}),
|
|
1351
|
+
className: "!bg-gridHeader",
|
|
1352
|
+
readonly: true,
|
|
1353
|
+
value: ""
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
getNewColumnCell() {
|
|
1358
|
+
return {
|
|
1359
|
+
[toPlaneCellIndex({
|
|
1360
|
+
col: 0,
|
|
1361
|
+
row: 0
|
|
1362
|
+
})]: {
|
|
1363
|
+
accessoryHtml: tableButtons.addColumn.render({
|
|
1364
|
+
disabled: (this.model.table.view?.target?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1365
|
+
}),
|
|
1366
|
+
className: "!bg-gridHeader",
|
|
1367
|
+
readonly: true,
|
|
1368
|
+
value: ""
|
|
1369
|
+
}
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
// packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
|
|
1375
|
+
import React6, { useCallback as useCallback3, useMemo as useMemo3, useRef } from "react";
|
|
1376
|
+
import { FormatEnum as FormatEnum5 } from "@dxos/echo-schema";
|
|
1377
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1378
|
+
import { cellQuery, editorKeys, parseCellIndex, useGridContext as useGridContext2, GridCellEditor } from "@dxos/react-ui-grid";
|
|
1379
|
+
|
|
1380
|
+
// packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
|
|
1381
|
+
import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
|
|
1382
|
+
import { EditorView } from "@codemirror/view";
|
|
1383
|
+
var completion = ({ debug, onQuery, onMatch }) => {
|
|
1384
|
+
return [
|
|
1385
|
+
EditorView.theme({
|
|
1386
|
+
".cm-completionDialog": {
|
|
1387
|
+
width: "var(--dx-gridCellWidth)"
|
|
1388
|
+
}
|
|
1389
|
+
}),
|
|
1390
|
+
autocompletion({
|
|
1391
|
+
icons: false,
|
|
1392
|
+
activateOnTyping: true,
|
|
1393
|
+
closeOnBlur: !debug,
|
|
1394
|
+
override: [
|
|
1395
|
+
async (context) => {
|
|
1396
|
+
const text = context.state.doc.toString();
|
|
1397
|
+
return {
|
|
1398
|
+
from: 0,
|
|
1399
|
+
options: await onQuery(text)
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
],
|
|
1403
|
+
// TODO(burdon): Consts from grid (to line-up with grid).
|
|
1404
|
+
tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
|
|
1405
|
+
optionClass: () => "flex h-[33px] items-center"
|
|
1406
|
+
}),
|
|
1407
|
+
// Check for accepted completion metadata in the transaction.
|
|
1408
|
+
EditorView.updateListener.of((update) => {
|
|
1409
|
+
update.transactions.forEach((tr) => {
|
|
1410
|
+
const completion2 = tr.annotation(pickedCompletion);
|
|
1411
|
+
if (completion2) {
|
|
1412
|
+
onMatch(completion2.data);
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
})
|
|
1416
|
+
];
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
// packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
|
|
1420
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
|
|
1421
|
+
var newValue = Symbol.for("newValue");
|
|
1422
|
+
var createOption = (text) => ({
|
|
1423
|
+
[newValue]: true,
|
|
1424
|
+
text
|
|
1425
|
+
});
|
|
1426
|
+
var isCreateOption = (data) => typeof data === "object" && data[newValue];
|
|
1427
|
+
var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
|
|
1428
|
+
const { id: gridId, editing, setEditing } = useGridContext2("TableCellEditor", __gridScope);
|
|
1429
|
+
const suppressNextBlur = useRef(false);
|
|
1430
|
+
const fieldProjection = useMemo3(() => {
|
|
1431
|
+
if (!model || !editing) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
const { col } = parseCellIndex(editing.index);
|
|
1435
|
+
const field = model.projection.view.fields[col];
|
|
1436
|
+
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
1437
|
+
invariant2(fieldProjection2, void 0, {
|
|
1438
|
+
F: __dxlog_file3,
|
|
1439
|
+
L: 67,
|
|
1440
|
+
S: void 0,
|
|
1441
|
+
A: [
|
|
1442
|
+
"fieldProjection",
|
|
1443
|
+
""
|
|
1444
|
+
]
|
|
1445
|
+
});
|
|
1446
|
+
return fieldProjection2;
|
|
1447
|
+
}, [
|
|
1448
|
+
model,
|
|
1449
|
+
editing
|
|
1450
|
+
]);
|
|
1451
|
+
const handleEnter = useCallback3((value) => {
|
|
1452
|
+
if (!model || !editing) {
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
const cell = parseCellIndex(editing.index);
|
|
1456
|
+
model.setCellData(cell, value);
|
|
1457
|
+
onEnter?.(cell);
|
|
1458
|
+
onFocus?.();
|
|
1459
|
+
setEditing(null);
|
|
1460
|
+
}, [
|
|
1461
|
+
model,
|
|
1462
|
+
editing
|
|
1463
|
+
]);
|
|
1464
|
+
const handleBlur = useCallback3((value) => {
|
|
1465
|
+
if (!model || !editing) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (suppressNextBlur.current) {
|
|
1469
|
+
suppressNextBlur.current = false;
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
const cell = parseCellIndex(editing.index);
|
|
1473
|
+
if (value !== void 0) {
|
|
1474
|
+
model.setCellData(cell, value);
|
|
1475
|
+
}
|
|
1476
|
+
}, [
|
|
1477
|
+
model,
|
|
1478
|
+
editing
|
|
1479
|
+
]);
|
|
1480
|
+
const handleClose = useCallback3((value, event) => {
|
|
1481
|
+
if (!model || !editing || !fieldProjection) {
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
const cell = parseCellIndex(editing.index);
|
|
1485
|
+
onEnter?.(cell);
|
|
1486
|
+
if (event && onFocus) {
|
|
1487
|
+
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
1488
|
+
}
|
|
1489
|
+
}, [
|
|
1490
|
+
model,
|
|
1491
|
+
editing,
|
|
1492
|
+
onFocus,
|
|
1493
|
+
onEnter,
|
|
1494
|
+
fieldProjection,
|
|
1495
|
+
determineNavigationAxis,
|
|
1496
|
+
determineNavigationDelta
|
|
1497
|
+
]);
|
|
1498
|
+
const extension = useMemo3(() => {
|
|
1499
|
+
if (!fieldProjection) {
|
|
1500
|
+
return [];
|
|
1501
|
+
}
|
|
1502
|
+
const extension2 = [
|
|
1503
|
+
editorKeys({
|
|
1504
|
+
onClose: handleClose,
|
|
1505
|
+
...editing?.initialContent && {
|
|
1506
|
+
onNav: handleClose
|
|
1507
|
+
}
|
|
1508
|
+
})
|
|
1509
|
+
];
|
|
1510
|
+
if (onQuery) {
|
|
1511
|
+
switch (fieldProjection.props.format) {
|
|
1512
|
+
case FormatEnum5.Ref: {
|
|
1513
|
+
extension2.push([
|
|
1514
|
+
completion({
|
|
1515
|
+
onQuery: (text) => onQuery(fieldProjection, text),
|
|
1516
|
+
onMatch: (data) => {
|
|
1517
|
+
if (model && editing && modals) {
|
|
1518
|
+
if (isCreateOption(data)) {
|
|
1519
|
+
const { field, props } = fieldProjection;
|
|
1520
|
+
if (props.referenceSchema) {
|
|
1521
|
+
suppressNextBlur.current = true;
|
|
1522
|
+
modals.openCreateRef(props.referenceSchema, document.querySelector(cellQuery(editing.index, gridId)), {
|
|
1523
|
+
[field.referencePath]: data.text
|
|
1524
|
+
}, (data2) => {
|
|
1525
|
+
handleEnter(data2);
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
} else {
|
|
1529
|
+
handleEnter(data);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
})
|
|
1534
|
+
]);
|
|
1535
|
+
break;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
return extension2;
|
|
1540
|
+
}, [
|
|
1541
|
+
model,
|
|
1542
|
+
modals,
|
|
1543
|
+
editing,
|
|
1544
|
+
fieldProjection,
|
|
1545
|
+
handleClose
|
|
1546
|
+
]);
|
|
1547
|
+
const getCellContent = useCallback3(() => {
|
|
1548
|
+
if (model && editing) {
|
|
1549
|
+
const value = model.getCellData(parseCellIndex(editing.index));
|
|
1550
|
+
return value !== void 0 ? String(value) : "";
|
|
1551
|
+
}
|
|
1552
|
+
}, [
|
|
1553
|
+
model,
|
|
1554
|
+
editing
|
|
1555
|
+
]);
|
|
1556
|
+
return /* @__PURE__ */ React6.createElement(GridCellEditor, {
|
|
1557
|
+
extension,
|
|
1558
|
+
getCellContent,
|
|
1559
|
+
onBlur: handleBlur
|
|
1560
|
+
});
|
|
1561
|
+
};
|
|
1562
|
+
var determineNavigationAxis = ({ key }) => {
|
|
1563
|
+
switch (key) {
|
|
1564
|
+
case "ArrowUp":
|
|
1565
|
+
case "ArrowDown":
|
|
1566
|
+
case "Enter": {
|
|
1567
|
+
return "row";
|
|
1568
|
+
}
|
|
1569
|
+
case "ArrowLeft":
|
|
1570
|
+
case "ArrowRight":
|
|
1571
|
+
case "Tab":
|
|
1572
|
+
return "col";
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
var determineNavigationDelta = ({ key, shift }) => {
|
|
1576
|
+
switch (key) {
|
|
1577
|
+
case "ArrowUp":
|
|
1578
|
+
case "ArrowLeft":
|
|
1579
|
+
return -1;
|
|
1580
|
+
case "ArrowDown":
|
|
1581
|
+
case "ArrowRight":
|
|
1582
|
+
return 1;
|
|
1583
|
+
}
|
|
1584
|
+
return shift ? -1 : 1;
|
|
1585
|
+
};
|
|
1586
|
+
|
|
1587
|
+
// packages/ui/react-ui-table/src/components/Table/Table.tsx
|
|
1588
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/Table/Table.tsx";
|
|
1589
|
+
var inlineEndLine = "[&>.dx-grid]:relative [&>.dx-grid]:after:absolute [&>.dx-grid]:after:inset-block-0 [&>.dx-grid]:after:-inline-end-px [&>.dx-grid]:after:is-px [&>.dx-grid]:after:bg-separator";
|
|
1590
|
+
var blockEndLine = "[&>.dx-grid]:before:absolute [&>.dx-grid]:before:inset-inline-0 [&>.dx-grid]:before:-block-end-px [&>.dx-grid]:before:bs-px [&>.dx-grid]:before:bg-separator";
|
|
1591
|
+
var frozen = {
|
|
1592
|
+
frozenRowsStart: 1,
|
|
1593
|
+
frozenColsStart: 1,
|
|
1594
|
+
frozenColsEnd: 1
|
|
1595
|
+
};
|
|
1596
|
+
var TableRoot = ({ children, role }) => {
|
|
1597
|
+
return /* @__PURE__ */ React7.createElement("div", {
|
|
1598
|
+
role: "none",
|
|
1599
|
+
className: mx2("relative border-bs !border-separator", role === "section" ? "attention-surface overflow-hidden [&_.dx-grid]:max-is-[--dx-grid-content-inline-size]" : "flex flex-col [&_.dx-grid]:grow [&_.dx-grid]:max-is-[--dx-grid-content-inline-size] [&_.dx-grid]:bs-0 [&_.dx-grid]:max-bs-[--dx-grid-content-block-size]")
|
|
1600
|
+
}, children);
|
|
1601
|
+
};
|
|
1602
|
+
var TableMain = /* @__PURE__ */ forwardRef(({ model, presentation, ignoreAttention }, forwardedRef) => {
|
|
1603
|
+
const [dxGrid, setDxGrid] = useState2(null);
|
|
1604
|
+
const { hasAttention } = useAttention(model?.table ? fullyQualifiedId(model.table) : "table");
|
|
1605
|
+
const { t } = useTranslation3(translationKey);
|
|
1606
|
+
const modals = useMemo4(() => new ModalController(), []);
|
|
1607
|
+
useImperativeHandle(forwardedRef, () => {
|
|
1608
|
+
if (!presentation || !dxGrid) {
|
|
1609
|
+
return {};
|
|
1610
|
+
}
|
|
1611
|
+
dxGrid.getCells = (range, plane) => presentation.getCells(range, plane);
|
|
1612
|
+
return {
|
|
1613
|
+
update: (cell) => {
|
|
1614
|
+
if (cell) {
|
|
1615
|
+
dxGrid.updateIfWithinBounds(cell);
|
|
1616
|
+
} else {
|
|
1617
|
+
dxGrid.updateCells(true);
|
|
1618
|
+
dxGrid.requestUpdate();
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
}, [
|
|
1623
|
+
presentation,
|
|
1624
|
+
dxGrid
|
|
1625
|
+
]);
|
|
1626
|
+
const handleGridClick = useCallback4((event) => {
|
|
1627
|
+
if (!modals) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
|
|
1631
|
+
const tableButtonElement = event.target.closest(buttonSelector);
|
|
1632
|
+
if (tableButtonElement) {
|
|
1633
|
+
const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
|
|
1634
|
+
if (!button) {
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
modals.setTrigger(tableButtonElement);
|
|
1638
|
+
const data = button.getData(tableButtonElement);
|
|
1639
|
+
switch (data.type) {
|
|
1640
|
+
case "rowMenu": {
|
|
1641
|
+
modals.showRowMenu(data.rowIndex);
|
|
1642
|
+
break;
|
|
1643
|
+
}
|
|
1644
|
+
case "columnSettings": {
|
|
1645
|
+
modals.showColumnMenu(data.fieldId);
|
|
1646
|
+
break;
|
|
1647
|
+
}
|
|
1648
|
+
case "newColumn": {
|
|
1649
|
+
modals.showColumnCreator();
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1652
|
+
case "referencedCell": {
|
|
1653
|
+
modals.showReferencePanel(data.targetId, data.schemaId);
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
case "sort": {
|
|
1657
|
+
model?.sorting?.toggleSort(data.fieldId);
|
|
1658
|
+
break;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
|
|
1664
|
+
const controlElement = event.target.closest(controlSelector);
|
|
1665
|
+
if (controlElement) {
|
|
1666
|
+
const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
|
|
1667
|
+
if (!control) {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
const data = control.getData(controlElement);
|
|
1671
|
+
switch (data.type) {
|
|
1672
|
+
case "checkbox": {
|
|
1673
|
+
if (data.header) {
|
|
1674
|
+
model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
|
|
1675
|
+
} else {
|
|
1676
|
+
model?.selection.toggleSelectionForRowIndex(data.rowIndex);
|
|
1677
|
+
}
|
|
1678
|
+
break;
|
|
1679
|
+
}
|
|
1680
|
+
case "switch": {
|
|
1681
|
+
if (model) {
|
|
1682
|
+
model.updateCellData({
|
|
1683
|
+
row: data.rowIndex,
|
|
1684
|
+
col: data.colIndex
|
|
1685
|
+
}, (value) => !value);
|
|
1686
|
+
}
|
|
1687
|
+
break;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}, [
|
|
1692
|
+
model,
|
|
1693
|
+
modals
|
|
1694
|
+
]);
|
|
1695
|
+
const handleFocus = useCallback4((increment, delta) => {
|
|
1696
|
+
if (dxGrid) {
|
|
1697
|
+
dxGrid.refocus(increment, delta);
|
|
1698
|
+
}
|
|
1699
|
+
}, [
|
|
1700
|
+
dxGrid
|
|
1701
|
+
]);
|
|
1702
|
+
const handleEnter = useCallback4((cell) => {
|
|
1703
|
+
if (model && cell.row === model.getRowCount() - 1) {
|
|
1704
|
+
model.insertRow(cell.row);
|
|
1705
|
+
if (dxGrid) {
|
|
1706
|
+
requestAnimationFrame(() => {
|
|
1707
|
+
dxGrid?.scrollToRow(cell.row + 1);
|
|
1708
|
+
dxGrid?.refocus("row", 1);
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}, [
|
|
1713
|
+
model,
|
|
1714
|
+
dxGrid
|
|
1715
|
+
]);
|
|
1716
|
+
const handleKeyDown = useCallback4((event) => {
|
|
1717
|
+
const cell = closestCell(event.target);
|
|
1718
|
+
if (!model || !cell) {
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
switch (event.key) {
|
|
1722
|
+
case "Backspace":
|
|
1723
|
+
case "Delete": {
|
|
1724
|
+
model.setCellData(cell, void 0);
|
|
1725
|
+
break;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}, [
|
|
1729
|
+
model
|
|
1730
|
+
]);
|
|
1731
|
+
const handleAxisResize = useCallback4((event) => {
|
|
1732
|
+
if (event.axis === "col") {
|
|
1733
|
+
const columnIndex = parseInt(event.index, 10);
|
|
1734
|
+
model?.setColumnWidth(columnIndex, event.size);
|
|
1735
|
+
}
|
|
1736
|
+
}, [
|
|
1737
|
+
model
|
|
1738
|
+
]);
|
|
1739
|
+
const handleWheel = useCallback4((event) => {
|
|
1740
|
+
if (!ignoreAttention && !hasAttention) {
|
|
1741
|
+
event.stopPropagation();
|
|
1742
|
+
}
|
|
1743
|
+
}, [
|
|
1744
|
+
hasAttention,
|
|
1745
|
+
ignoreAttention
|
|
1746
|
+
]);
|
|
1747
|
+
const handleNewColumn = useCallback4(() => {
|
|
1748
|
+
const columns = model?.getColumnCount();
|
|
1749
|
+
if (dxGrid && columns) {
|
|
1750
|
+
dxGrid.scrollToColumn(columns - 1);
|
|
1751
|
+
}
|
|
1752
|
+
}, [
|
|
1753
|
+
model,
|
|
1754
|
+
dxGrid
|
|
1755
|
+
]);
|
|
1756
|
+
const handleQuery = useCallback4(async ({ field, props }, text) => {
|
|
1757
|
+
if (model && props.referenceSchema && field.referencePath) {
|
|
1758
|
+
const space = getSpace4(model.table);
|
|
1759
|
+
invariant3(space, void 0, {
|
|
1760
|
+
F: __dxlog_file4,
|
|
1761
|
+
L: 264,
|
|
1762
|
+
S: void 0,
|
|
1763
|
+
A: [
|
|
1764
|
+
"space",
|
|
1765
|
+
""
|
|
1766
|
+
]
|
|
1767
|
+
});
|
|
1768
|
+
const schema = space.db.schemaRegistry.getSchema(props.referenceSchema);
|
|
1769
|
+
if (schema) {
|
|
1770
|
+
const { objects } = await space.db.query(Filter.schema(schema)).run();
|
|
1771
|
+
const options = objects.map((obj) => {
|
|
1772
|
+
const value = getValue4(obj, field.referencePath);
|
|
1773
|
+
if (!value || typeof value !== "string") {
|
|
1774
|
+
return void 0;
|
|
1775
|
+
}
|
|
1776
|
+
return {
|
|
1777
|
+
label: value,
|
|
1778
|
+
data: obj
|
|
1779
|
+
};
|
|
1780
|
+
}).filter(isNotFalsy);
|
|
1781
|
+
return [
|
|
1782
|
+
...options,
|
|
1783
|
+
{
|
|
1784
|
+
label: t("create new object label", {
|
|
1785
|
+
text
|
|
1786
|
+
}),
|
|
1787
|
+
data: createOption(text)
|
|
1788
|
+
}
|
|
1789
|
+
];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return [];
|
|
1793
|
+
}, [
|
|
1794
|
+
model
|
|
1795
|
+
]);
|
|
1796
|
+
if (!model || !modals) {
|
|
1797
|
+
return /* @__PURE__ */ React7.createElement("span", {
|
|
1798
|
+
role: "none",
|
|
1799
|
+
className: "attention-surface"
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
return /* @__PURE__ */ React7.createElement(Grid.Root, {
|
|
1803
|
+
id: model.table.id ?? "table-grid"
|
|
1804
|
+
}, /* @__PURE__ */ React7.createElement(TableCellEditor, {
|
|
1805
|
+
model,
|
|
1806
|
+
modals,
|
|
1807
|
+
onEnter: handleEnter,
|
|
1808
|
+
onFocus: handleFocus,
|
|
1809
|
+
onQuery: handleQuery
|
|
1810
|
+
}), /* @__PURE__ */ React7.createElement(Grid.Content, {
|
|
1811
|
+
onWheelCapture: handleWheel,
|
|
1812
|
+
className: mx2("[--dx-grid-base:var(--surface-bg)]", inlineEndLine, blockEndLine),
|
|
1813
|
+
frozen,
|
|
1814
|
+
columns: model.columnMeta.value,
|
|
1815
|
+
limitRows: model.getRowCount() ?? 0,
|
|
1816
|
+
limitColumns: model.table.view?.target?.fields?.length ?? 0,
|
|
1817
|
+
onAxisResize: handleAxisResize,
|
|
1818
|
+
onClick: handleGridClick,
|
|
1819
|
+
onKeyDown: handleKeyDown,
|
|
1820
|
+
overscroll: "trap",
|
|
1821
|
+
ref: setDxGrid
|
|
1822
|
+
}), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
|
|
1823
|
+
model,
|
|
1824
|
+
modals
|
|
1825
|
+
}), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
|
|
1826
|
+
model,
|
|
1827
|
+
modals
|
|
1828
|
+
}), /* @__PURE__ */ React7.createElement(ColumnSettings, {
|
|
1829
|
+
model,
|
|
1830
|
+
modals,
|
|
1831
|
+
onNewColumn: handleNewColumn
|
|
1832
|
+
}), /* @__PURE__ */ React7.createElement(RefPanel, {
|
|
1833
|
+
model,
|
|
1834
|
+
modals
|
|
1835
|
+
}), /* @__PURE__ */ React7.createElement(CreateRefPanel, {
|
|
1836
|
+
model,
|
|
1837
|
+
modals
|
|
1838
|
+
}));
|
|
1839
|
+
});
|
|
1840
|
+
var Table = {
|
|
1841
|
+
Root: TableRoot,
|
|
1842
|
+
Main: TableMain
|
|
1843
|
+
};
|
|
1844
|
+
|
|
1845
|
+
// packages/ui/react-ui-table/src/components/TableToolbar/TableToolbar.tsx
|
|
1846
|
+
import React8, { useCallback as useCallback5, useMemo as useMemo5 } from "react";
|
|
1847
|
+
import { create as create3 } from "@dxos/live-object";
|
|
1848
|
+
import { createGapSeparator, createMenuAction, MenuProvider, ToolbarMenu, useMenuActions } from "@dxos/react-ui-menu";
|
|
1849
|
+
var createTableToolbarActions = (state) => {
|
|
1850
|
+
const add = createMenuAction("add-row", {
|
|
1851
|
+
type: "add-row",
|
|
1852
|
+
icon: "ph--plus--regular",
|
|
1853
|
+
label: [
|
|
1854
|
+
"add row",
|
|
1855
|
+
{
|
|
1856
|
+
ns: translationKey
|
|
1857
|
+
}
|
|
1858
|
+
],
|
|
1859
|
+
testId: "table.toolbar.add-row"
|
|
1860
|
+
});
|
|
1861
|
+
const save = createMenuAction("save-view", {
|
|
1862
|
+
type: "save-view",
|
|
1863
|
+
icon: "ph--floppy-disk--regular",
|
|
1864
|
+
label: [
|
|
1865
|
+
"save view label",
|
|
1866
|
+
{
|
|
1867
|
+
ns: translationKey
|
|
1868
|
+
}
|
|
1869
|
+
],
|
|
1870
|
+
testId: "table.toolbar.save-view",
|
|
1871
|
+
iconOnly: false,
|
|
1872
|
+
hidden: !state.viewDirty
|
|
1873
|
+
});
|
|
1874
|
+
const gap = createGapSeparator();
|
|
1875
|
+
const comment = createMenuAction("comment", {
|
|
1876
|
+
type: "comment",
|
|
1877
|
+
icon: "ph--chat-text--regular",
|
|
1878
|
+
label: [
|
|
1879
|
+
"create comment",
|
|
1880
|
+
{
|
|
1881
|
+
ns: translationKey
|
|
1882
|
+
}
|
|
1883
|
+
],
|
|
1884
|
+
testId: "table.toolbar.comment"
|
|
1885
|
+
});
|
|
1886
|
+
const nodes = [
|
|
1887
|
+
add,
|
|
1888
|
+
save,
|
|
1889
|
+
...gap.nodes,
|
|
1890
|
+
comment
|
|
1891
|
+
];
|
|
1892
|
+
return {
|
|
1893
|
+
nodes,
|
|
1894
|
+
edges: nodes.map(({ id: target }) => ({
|
|
1895
|
+
source: "root",
|
|
1896
|
+
target
|
|
1897
|
+
}))
|
|
1898
|
+
};
|
|
1899
|
+
};
|
|
1900
|
+
var TableToolbar = ({ classNames, viewDirty, attendableId, onAction }) => {
|
|
1901
|
+
const state = useMemo5(() => create3({
|
|
1902
|
+
viewDirty
|
|
1903
|
+
}), []);
|
|
1904
|
+
const actionsCreator = useCallback5(() => createTableToolbarActions(state), [
|
|
1905
|
+
state
|
|
1906
|
+
]);
|
|
1907
|
+
const menu = useMenuActions(actionsCreator);
|
|
1908
|
+
return /* @__PURE__ */ React8.createElement(MenuProvider, {
|
|
1909
|
+
...menu,
|
|
1910
|
+
attendableId,
|
|
1911
|
+
onAction
|
|
1912
|
+
}, /* @__PURE__ */ React8.createElement(ToolbarMenu, {
|
|
1913
|
+
classNames
|
|
1914
|
+
}));
|
|
1915
|
+
};
|
|
1916
|
+
|
|
1917
|
+
// packages/ui/react-ui-table/src/hooks/useTableModel.ts
|
|
1918
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
1588
1919
|
var useTableModel = ({ objects, table, projection, ...props }) => {
|
|
1589
1920
|
const [model, setModel] = useState3();
|
|
1590
1921
|
useEffect2(() => {
|
|
@@ -1620,15 +1951,22 @@ var useTableModel = ({ objects, table, projection, ...props }) => {
|
|
|
1620
1951
|
return model;
|
|
1621
1952
|
};
|
|
1622
1953
|
export {
|
|
1954
|
+
BUTTON_IDENTIFIERS,
|
|
1955
|
+
CONTROL_IDENTIFIERS,
|
|
1956
|
+
ModalController,
|
|
1623
1957
|
Table,
|
|
1958
|
+
TableModel,
|
|
1959
|
+
TablePresentation,
|
|
1624
1960
|
TableSchema,
|
|
1961
|
+
TableToolbar,
|
|
1625
1962
|
TableType,
|
|
1626
|
-
Toolbar,
|
|
1627
1963
|
initializeTable,
|
|
1964
|
+
renderCheckbox,
|
|
1965
|
+
renderSwitch,
|
|
1628
1966
|
tableButtons,
|
|
1967
|
+
tableControls,
|
|
1629
1968
|
touch,
|
|
1630
1969
|
translations_default as translations,
|
|
1631
|
-
useTableModel
|
|
1632
|
-
useToolbarContext
|
|
1970
|
+
useTableModel
|
|
1633
1971
|
};
|
|
1634
1972
|
//# sourceMappingURL=index.mjs.map
|