@dxos/react-ui-table 0.8.3 → 0.8.4-main.1c7ec43d41
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-FBURZBPH.mjs +70 -0
- package/dist/lib/browser/chunk-FBURZBPH.mjs.map +7 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
- package/dist/lib/browser/chunk-YGC7LZJN.mjs +1695 -0
- package/dist/lib/browser/chunk-YGC7LZJN.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1165 -2554
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +115 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/browser/translations.mjs +36 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +4 -5
- package/dist/lib/node-esm/chunk-DKKMSVKP.mjs +71 -0
- package/dist/lib/node-esm/chunk-DKKMSVKP.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-GKIWDEZ7.mjs +1697 -0
- package/dist/lib/node-esm/chunk-GKIWDEZ7.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1165 -2554
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +116 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- package/dist/lib/node-esm/translations.mjs +37 -0
- package/dist/lib/node-esm/translations.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +4 -5
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts +2 -3
- package/dist/types/src/components/Table/ColumnActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/ColumnSettings.d.ts +4 -2
- package/dist/types/src/components/Table/ColumnSettings.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.d.ts +7 -7
- package/dist/types/src/components/Table/DynamicTable.d.ts.map +1 -1
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts +35 -3
- package/dist/types/src/components/Table/DynamicTable.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/Relations.stories.d.ts +111 -0
- package/dist/types/src/components/Table/Relations.stories.d.ts.map +1 -0
- package/dist/types/src/components/Table/RowActionsMenu.d.ts +1 -1
- package/dist/types/src/components/Table/RowActionsMenu.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.d.ts +21 -18
- package/dist/types/src/components/Table/Table.d.ts.map +1 -1
- package/dist/types/src/components/Table/Table.stories.d.ts +110 -6
- package/dist/types/src/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/types/src/components/Table/TableContent.d.ts +17 -0
- package/dist/types/src/components/Table/TableContent.d.ts.map +1 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts +21 -0
- package/dist/types/src/components/Table/TableToolbar.d.ts.map +1 -0
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts +2 -1
- package/dist/types/src/components/TableCellEditor/CellValidationMessage.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts +14 -9
- package/dist/types/src/components/TableCellEditor/FormCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts +12 -18
- package/dist/types/src/components/TableCellEditor/TableCellEditor.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts +38 -5
- package/dist/types/src/components/TableCellEditor/TableCellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TableCellEditor/index.d.ts +1 -0
- package/dist/types/src/components/TableCellEditor/index.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +26 -56
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useAddRow.d.ts +13 -0
- package/dist/types/src/hooks/useAddRow.d.ts.map +1 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts +6 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useTableModel.d.ts +11 -10
- package/dist/types/src/hooks/useTableModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/model/modal-controller.d.ts +5 -8
- package/dist/types/src/model/modal-controller.d.ts.map +1 -1
- package/dist/types/src/model/selection-model.d.ts +18 -8
- package/dist/types/src/model/selection-model.d.ts.map +1 -1
- package/dist/types/src/model/table-model.d.ts +150 -32
- package/dist/types/src/model/table-model.d.ts.map +1 -1
- package/dist/types/src/model/table-presentation.d.ts +13 -2
- package/dist/types/src/model/table-presentation.d.ts.map +1 -1
- 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/playwright/playwright.config.d.ts +3 -0
- package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/useTestTableModel.d.ts +25 -0
- package/dist/types/src/testing/useTestTableModel.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +22 -25
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Table.d.ts +26 -0
- package/dist/types/src/types/Table.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.d.ts +15 -14
- package/dist/types/src/util/dynamic-table.d.ts.map +1 -1
- package/dist/types/src/util/dynamic-table.test.d.ts +2 -0
- package/dist/types/src/util/dynamic-table.test.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +2 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/query-ast.d.ts +7 -0
- package/dist/types/src/util/query-ast.d.ts.map +1 -0
- package/dist/types/src/util/schema.d.ts +1 -1
- package/dist/types/src/util/schema.d.ts.map +1 -1
- package/dist/types/src/util/signals.d.ts.map +1 -1
- package/dist/types/src/util/sort.d.ts +12 -0
- package/dist/types/src/util/sort.d.ts.map +1 -0
- package/dist/types/src/util/table-buttons.d.ts +31 -17
- package/dist/types/src/util/table-buttons.d.ts.map +1 -1
- package/dist/types/src/util/table-controls.d.ts +4 -4
- package/dist/types/src/util/table-controls.d.ts.map +1 -1
- package/dist/types/src/util/tag.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +76 -72
- package/src/components/Table/ColumnActionsMenu.tsx +18 -13
- package/src/components/Table/ColumnSettings.tsx +18 -15
- package/src/components/Table/DynamicTable.stories.tsx +40 -36
- package/src/components/Table/DynamicTable.tsx +38 -34
- package/src/components/Table/Relations.stories.tsx +281 -0
- package/src/components/Table/RowActionsMenu.tsx +29 -19
- package/src/components/Table/Table.stories.tsx +198 -214
- package/src/components/Table/Table.tsx +47 -363
- package/src/components/Table/TableContent.tsx +421 -0
- package/src/components/Table/TableToolbar.tsx +111 -0
- package/src/components/TableCellEditor/CellValidationMessage.tsx +9 -4
- package/src/components/TableCellEditor/FormCellEditor.tsx +153 -49
- package/src/components/TableCellEditor/TableCellEditor.stories.tsx +40 -79
- package/src/components/TableCellEditor/TableCellEditor.tsx +109 -199
- package/src/components/TableCellEditor/index.ts +1 -0
- package/src/components/index.ts +0 -1
- package/src/components/testing.ts +46 -37
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useAddRow.ts +36 -0
- package/src/hooks/useProjectionModel.ts +39 -0
- package/src/hooks/useTableModel.ts +41 -35
- package/src/index.ts +0 -5
- package/src/model/modal-controller.ts +24 -41
- package/src/model/selection-model.ts +75 -41
- package/src/model/table-model.test.ts +91 -56
- package/src/model/table-model.ts +629 -162
- package/src/model/table-presentation.test.ts +69 -59
- package/src/model/table-presentation.ts +283 -154
- package/src/playwright/TableManager.ts +13 -6
- package/src/playwright/playwright.config.ts +17 -0
- package/src/playwright/smoke.spec.ts +181 -42
- package/src/testing/index.ts +5 -0
- package/src/testing/useTestTableModel.ts +133 -0
- package/src/translations.ts +24 -24
- package/src/types/Table.ts +79 -0
- package/src/types/index.ts +2 -2
- package/src/util/dynamic-table.test.ts +70 -0
- package/src/util/dynamic-table.ts +51 -36
- package/src/util/index.ts +2 -1
- package/src/util/query-ast.ts +22 -0
- package/src/util/schema.ts +4 -4
- package/src/util/sort.ts +90 -0
- package/src/util/table-buttons.ts +28 -4
- package/src/util/table-controls.ts +6 -3
- package/dist/lib/browser/chunk-TL7CKQQV.mjs +0 -27
- package/dist/lib/browser/chunk-TL7CKQQV.mjs.map +0 -7
- package/dist/lib/node/chunk-O2VPBNS5.cjs +0 -50
- package/dist/lib/node/chunk-O2VPBNS5.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -2739
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/types/index.cjs +0 -31
- package/dist/lib/node/types/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-GBT6GD4G.mjs +0 -29
- package/dist/lib/node-esm/chunk-GBT6GD4G.mjs.map +0 -7
- package/dist/types/src/components/Table/CreateRefPanel.d.ts +0 -9
- package/dist/types/src/components/Table/CreateRefPanel.d.ts.map +0 -1
- package/dist/types/src/components/Table/relations.stories.d.ts +0 -9
- package/dist/types/src/components/Table/relations.stories.d.ts.map +0 -1
- package/dist/types/src/components/TableCellEditor/extension.d.ts +0 -13
- package/dist/types/src/components/TableCellEditor/extension.d.ts.map +0 -1
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts +0 -21
- package/dist/types/src/components/TableToolbar/TableToolbar.d.ts.map +0 -1
- package/dist/types/src/components/TableToolbar/index.d.ts +0 -2
- package/dist/types/src/components/TableToolbar/index.d.ts.map +0 -1
- package/dist/types/src/model/table-sorting.d.ts +0 -53
- package/dist/types/src/model/table-sorting.d.ts.map +0 -1
- package/dist/types/src/types/table.d.ts +0 -56
- package/dist/types/src/types/table.d.ts.map +0 -1
- package/dist/types/src/util/table.d.ts +0 -14
- package/dist/types/src/util/table.d.ts.map +0 -1
- package/src/components/Table/CreateRefPanel.tsx +0 -84
- package/src/components/Table/relations.stories.tsx +0 -124
- package/src/components/TableCellEditor/extension.ts +0 -61
- package/src/components/TableToolbar/TableToolbar.tsx +0 -102
- package/src/components/TableToolbar/index.ts +0 -5
- package/src/model/table-sorting.ts +0 -216
- package/src/playwright/playwright.config.cts +0 -18
- package/src/types/table.ts +0 -27
- package/src/util/table.ts +0 -127
|
@@ -1,310 +1,56 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
BUTTON_IDENTIFIERS,
|
|
3
|
+
CONTROL_IDENTIFIERS,
|
|
4
|
+
CheckboxStory,
|
|
5
|
+
SwitchStory,
|
|
6
|
+
TableModel,
|
|
7
|
+
TablePresentation,
|
|
8
|
+
cellClassesForRowSelection,
|
|
9
|
+
compareValues,
|
|
10
|
+
createDirectChangeCallback,
|
|
11
|
+
createEchoChangeCallback,
|
|
12
|
+
extractOrder,
|
|
13
|
+
getSortValue,
|
|
14
|
+
tableButtons,
|
|
15
|
+
tableControls,
|
|
16
|
+
useAddRow,
|
|
17
|
+
useProjectionModel,
|
|
18
|
+
useTableModel
|
|
19
|
+
} from "./chunk-YGC7LZJN.mjs";
|
|
20
|
+
import {
|
|
21
|
+
Table_exports
|
|
22
|
+
} from "./chunk-FBURZBPH.mjs";
|
|
23
|
+
import "./chunk-J5LGTIGS.mjs";
|
|
5
24
|
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"en-US": {
|
|
11
|
-
[translationKey]: {
|
|
12
|
-
"object placeholder": "New table",
|
|
13
|
-
"create object label": "Create table",
|
|
14
|
-
"table name placeholder": "Table name",
|
|
15
|
-
"settings title": "Table settings",
|
|
16
|
-
"table schema label": "Schema",
|
|
17
|
-
"new schema": "New schema",
|
|
18
|
-
"continue label": "Continue",
|
|
19
|
-
"create stack section label": "Create table",
|
|
20
|
-
"add row label": "Add row",
|
|
21
|
-
"create comment": "Create thread",
|
|
22
|
-
"column action sort descending": "Sort Descending",
|
|
23
|
-
"column action sort ascending": "Sort Ascending",
|
|
24
|
-
"column action clear sorting": "Clear Sorting",
|
|
25
|
-
"column action settings": "Column Settings",
|
|
26
|
-
"column action delete": "Delete Column",
|
|
27
|
-
"delete row label": "Delete row",
|
|
28
|
-
"bulk delete row label": "Delete selected rows",
|
|
29
|
-
"column deleted label": "Column deleted",
|
|
30
|
-
"new column button label": "Create column",
|
|
31
|
-
"create new object label": "Create new object \u201C{{text}}\u201D",
|
|
32
|
-
"save view label": "Save changes to view"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
];
|
|
25
|
+
// src/components/Table/Table.tsx
|
|
26
|
+
import { Atom as Atom4 } from "@effect-atom/atom-react";
|
|
27
|
+
import { createContext } from "@radix-ui/react-context";
|
|
28
|
+
import React9, { forwardRef, useImperativeHandle, useRef as useRef3 } from "react";
|
|
37
29
|
|
|
38
|
-
//
|
|
39
|
-
import {
|
|
40
|
-
import
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { Filter } from "@dxos/react-client/echo";
|
|
44
|
-
import { useTranslation as useTranslation3 } from "@dxos/react-ui";
|
|
30
|
+
// src/components/Table/TableContent.tsx
|
|
31
|
+
import { Atom as Atom2, RegistryContext, useAtomValue as useAtomValue4 } from "@effect-atom/atom-react";
|
|
32
|
+
import * as String2 from "effect/String";
|
|
33
|
+
import React7, { useCallback as useCallback4, useContext, useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
|
|
34
|
+
import { log } from "@dxos/log";
|
|
45
35
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
46
|
-
import { closestCell,
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
// packages/ui/react-ui-table/src/components/Table/ColumnActionsMenu.tsx
|
|
51
|
-
import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
|
|
52
|
-
import React from "react";
|
|
53
|
-
import { DropdownMenu, useTranslation } from "@dxos/react-ui";
|
|
54
|
-
var ColumnActionsMenu = ({ model, modals }) => {
|
|
55
|
-
var _effect = _useSignals();
|
|
56
|
-
try {
|
|
57
|
-
const { t } = useTranslation(translationKey);
|
|
58
|
-
const state = modals.state.value;
|
|
59
|
-
if (state?.type !== "column") {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
const currentSort = model.sorting?.sorting;
|
|
63
|
-
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
64
|
-
return /* @__PURE__ */ React.createElement(DropdownMenu.Root, {
|
|
65
|
-
modal: false,
|
|
66
|
-
open: true,
|
|
67
|
-
onOpenChange: modals.close
|
|
68
|
-
}, /* @__PURE__ */ React.createElement(DropdownMenu.VirtualTrigger, {
|
|
69
|
-
virtualRef: modals.trigger
|
|
70
|
-
}), /* @__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, {
|
|
71
|
-
"data-testid": "column-sort-descending",
|
|
72
|
-
onClick: () => model.sorting?.setSort(state.fieldId, "desc")
|
|
73
|
-
}, t("column action sort descending")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
74
|
-
"data-testid": "column-sort-ascending",
|
|
75
|
-
onClick: () => model.sorting?.setSort(state.fieldId, "asc")
|
|
76
|
-
}, t("column action sort ascending")), isCurrentColumnSorted && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
77
|
-
"data-testid": "column-clear-sort",
|
|
78
|
-
onClick: () => model.sorting?.clearSort()
|
|
79
|
-
}, t("column action clear sorting")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
80
|
-
"data-testid": "column-delete",
|
|
81
|
-
onClick: () => model.deleteColumn(state.fieldId)
|
|
82
|
-
}, t("column action delete")), model.features.schemaEditable && /* @__PURE__ */ React.createElement(DropdownMenu.Item, {
|
|
83
|
-
"data-testid": "column-settings",
|
|
84
|
-
onClick: () => modals.openColumnSettings()
|
|
85
|
-
}, t("column action settings"))), /* @__PURE__ */ React.createElement(DropdownMenu.Arrow, null))));
|
|
86
|
-
} finally {
|
|
87
|
-
_effect.f();
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// packages/ui/react-ui-table/src/components/Table/ColumnSettings.tsx
|
|
92
|
-
import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
|
|
93
|
-
import React2, { useCallback, useEffect, useMemo, useState } from "react";
|
|
94
|
-
import { Popover } from "@dxos/react-ui";
|
|
95
|
-
import { FieldEditor } from "@dxos/react-ui-form";
|
|
96
|
-
var ColumnSettings = ({ model, modals, onNewColumn }) => {
|
|
97
|
-
var _effect = _useSignals2();
|
|
98
|
-
try {
|
|
99
|
-
const [newField, setNewField] = useState();
|
|
100
|
-
const state = modals.state.value;
|
|
101
|
-
const space = model?.space;
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
|
|
104
|
-
setNewField(model.projection.createFieldProjection());
|
|
105
|
-
requestAnimationFrame(() => {
|
|
106
|
-
onNewColumn();
|
|
107
|
-
});
|
|
108
|
-
} else {
|
|
109
|
-
setNewField(void 0);
|
|
110
|
-
}
|
|
111
|
-
}, [
|
|
112
|
-
model?.projection,
|
|
113
|
-
state
|
|
114
|
-
]);
|
|
115
|
-
const existingField = useMemo(() => {
|
|
116
|
-
if (state?.type === "columnSettings") {
|
|
117
|
-
const { mode } = state;
|
|
118
|
-
if (mode.type === "edit") {
|
|
119
|
-
return model?.view?.fields.find((f) => f.id === mode.fieldId);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return void 0;
|
|
123
|
-
}, [
|
|
124
|
-
model?.view?.fields,
|
|
125
|
-
state
|
|
126
|
-
]);
|
|
127
|
-
const field = existingField ?? newField;
|
|
128
|
-
const handleSave = useCallback(() => {
|
|
129
|
-
modals.close();
|
|
130
|
-
}, [
|
|
131
|
-
modals
|
|
132
|
-
]);
|
|
133
|
-
const handleCancel = useCallback(() => {
|
|
134
|
-
if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
|
|
135
|
-
model?.projection?.deleteFieldProjection(newField.id);
|
|
136
|
-
}
|
|
137
|
-
}, [
|
|
138
|
-
model?.projection,
|
|
139
|
-
state,
|
|
140
|
-
newField
|
|
141
|
-
]);
|
|
142
|
-
if (!model?.view || !model.projection || !field) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
return /* @__PURE__ */ React2.createElement(Popover.Root, {
|
|
146
|
-
modal: false,
|
|
147
|
-
open: state?.type === "columnSettings"
|
|
148
|
-
}, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
|
|
149
|
-
virtualRef: modals.trigger
|
|
150
|
-
}), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
|
|
151
|
-
classNames: "md:is-64"
|
|
152
|
-
}, /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(FieldEditor, {
|
|
153
|
-
view: model.view,
|
|
154
|
-
projection: model.projection,
|
|
155
|
-
field,
|
|
156
|
-
registry: space?.db.schemaRegistry,
|
|
157
|
-
onSave: handleSave,
|
|
158
|
-
onCancel: handleCancel
|
|
159
|
-
})), /* @__PURE__ */ React2.createElement(Popover.Arrow, null))));
|
|
160
|
-
} finally {
|
|
161
|
-
_effect.f();
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// packages/ui/react-ui-table/src/components/Table/CreateRefPanel.tsx
|
|
166
|
-
import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
|
|
167
|
-
import { Schema } from "effect";
|
|
168
|
-
import React3, { useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
169
|
-
import { live } from "@dxos/react-client/echo";
|
|
170
|
-
import { Popover as Popover2 } from "@dxos/react-ui";
|
|
171
|
-
import { Form } from "@dxos/react-ui-form";
|
|
172
|
-
import { useGridContext } from "@dxos/react-ui-grid";
|
|
173
|
-
var CreateRefPanel = ({ model, modals, __gridScope }) => {
|
|
174
|
-
var _effect = _useSignals3();
|
|
175
|
-
try {
|
|
176
|
-
const { id: gridId } = useGridContext("TableCellEditor", __gridScope);
|
|
177
|
-
const space = model?.space;
|
|
178
|
-
const state = modals.state.value;
|
|
179
|
-
const schema = useMemo2(() => {
|
|
180
|
-
if (!space || state?.type !== "createRefPanel") {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const [schema2] = space.db.schemaRegistry.query({
|
|
184
|
-
typename: state.typename
|
|
185
|
-
}).runSync();
|
|
186
|
-
if (schema2) {
|
|
187
|
-
const omit = Schema.omit("id");
|
|
188
|
-
return omit(schema2);
|
|
189
|
-
}
|
|
190
|
-
}, [
|
|
191
|
-
space,
|
|
192
|
-
state
|
|
193
|
-
]);
|
|
194
|
-
const handleSave = useCallback2((values) => {
|
|
195
|
-
if (!model || !space || state?.type !== "createRefPanel") {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
const [schema2] = space.db.schemaRegistry.query({
|
|
199
|
-
typename: state.typename
|
|
200
|
-
}).runSync();
|
|
201
|
-
if (schema2) {
|
|
202
|
-
const obj = space.db.add(live(schema2, values));
|
|
203
|
-
state.onCreate?.(obj);
|
|
204
|
-
}
|
|
205
|
-
void modals.close();
|
|
206
|
-
}, [
|
|
207
|
-
modals,
|
|
208
|
-
space,
|
|
209
|
-
state
|
|
210
|
-
]);
|
|
211
|
-
const handleCancel = useCallback2(() => {
|
|
212
|
-
if (model) {
|
|
213
|
-
modals.close();
|
|
214
|
-
}
|
|
215
|
-
}, [
|
|
216
|
-
modals
|
|
217
|
-
]);
|
|
218
|
-
if (!model?.view || !model.projection) {
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
|
-
return /* @__PURE__ */ React3.createElement(Popover2.Root, {
|
|
222
|
-
modal: false,
|
|
223
|
-
open: state?.type === "createRefPanel" && !!schema,
|
|
224
|
-
onOpenChange: (nextOpen) => {
|
|
225
|
-
if (model && !nextOpen) {
|
|
226
|
-
return modals.close();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}, /* @__PURE__ */ React3.createElement(Popover2.VirtualTrigger, {
|
|
230
|
-
virtualRef: modals.trigger
|
|
231
|
-
}), /* @__PURE__ */ React3.createElement(Popover2.Portal, null, /* @__PURE__ */ React3.createElement(Popover2.Content, {
|
|
232
|
-
classNames: "md:is-64",
|
|
233
|
-
"data-grid": gridId
|
|
234
|
-
}, /* @__PURE__ */ React3.createElement(Popover2.Viewport, null, state?.type === "createRefPanel" && schema && /* @__PURE__ */ React3.createElement(Form, {
|
|
235
|
-
schema,
|
|
236
|
-
values: state.initialValues ?? {},
|
|
237
|
-
onSave: handleSave,
|
|
238
|
-
onCancel: handleCancel
|
|
239
|
-
})), /* @__PURE__ */ React3.createElement(Popover2.Arrow, null))));
|
|
240
|
-
} finally {
|
|
241
|
-
_effect.f();
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
// packages/ui/react-ui-table/src/components/Table/RowActionsMenu.tsx
|
|
246
|
-
import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
|
|
247
|
-
import React4 from "react";
|
|
248
|
-
import { DropdownMenu as DropdownMenu2, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
249
|
-
var RowActionsMenu = ({ model, modals }) => {
|
|
250
|
-
var _effect = _useSignals4();
|
|
251
|
-
try {
|
|
252
|
-
const { t } = useTranslation2(translationKey);
|
|
253
|
-
const hasSelection = model.selection.hasSelection.value;
|
|
254
|
-
const state = modals.state.value;
|
|
255
|
-
if (state?.type !== "row") {
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
return /* @__PURE__ */ React4.createElement(DropdownMenu2.Root, {
|
|
259
|
-
modal: false,
|
|
260
|
-
open: true,
|
|
261
|
-
onOpenChange: modals.close
|
|
262
|
-
}, /* @__PURE__ */ React4.createElement(DropdownMenu2.VirtualTrigger, {
|
|
263
|
-
virtualRef: modals.trigger
|
|
264
|
-
}), /* @__PURE__ */ React4.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu2.Viewport, null, model.features.dataEditable !== false && /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
|
|
265
|
-
"data-testid": "row-menu-delete",
|
|
266
|
-
onClick: () => model.deleteRow(state.rowIndex)
|
|
267
|
-
}, t(hasSelection ? "bulk delete row label" : "delete row label")), model.rowActions?.map((action) => /* @__PURE__ */ React4.createElement(DropdownMenu2.Item, {
|
|
268
|
-
key: action.id,
|
|
269
|
-
"data-testid": `row-action-${action.id}`,
|
|
270
|
-
onClick: () => {
|
|
271
|
-
modals.close();
|
|
272
|
-
model.handleRowAction(action.id, state.rowIndex);
|
|
273
|
-
}
|
|
274
|
-
}, t(action.translationKey)))), /* @__PURE__ */ React4.createElement(DropdownMenu2.Arrow, null)));
|
|
275
|
-
} finally {
|
|
276
|
-
_effect.f();
|
|
277
|
-
}
|
|
278
|
-
};
|
|
36
|
+
import { Grid, closestCell, gridSeparatorBlockEnd, gridSeparatorInlineEnd } from "@dxos/react-ui-grid";
|
|
37
|
+
import { DxEditRequest } from "@dxos/react-ui-grid";
|
|
38
|
+
import { composable, composableProps, mx } from "@dxos/ui-theme";
|
|
279
39
|
|
|
280
|
-
//
|
|
281
|
-
import {
|
|
282
|
-
import {
|
|
283
|
-
|
|
284
|
-
import { invariant } from "@dxos/invariant";
|
|
285
|
-
import { isLiveObject, makeRef } from "@dxos/live-object";
|
|
286
|
-
import { formatForEditing, parseValue } from "@dxos/react-ui-form";
|
|
287
|
-
import { validateSchema } from "@dxos/schema";
|
|
288
|
-
|
|
289
|
-
// packages/ui/react-ui-table/src/model/selection-model.ts
|
|
290
|
-
import { computed, effect, signal } from "@preact/signals-core";
|
|
291
|
-
import { Resource } from "@dxos/context";
|
|
292
|
-
|
|
293
|
-
// packages/ui/react-ui-table/src/util/dynamic-table.ts
|
|
294
|
-
import { Obj, Ref } from "@dxos/echo";
|
|
295
|
-
import { getTypename, toJsonSchema } from "@dxos/echo-schema";
|
|
296
|
-
import { createView, getSchemaFromPropertyDefinitions, ViewProjection } from "@dxos/schema";
|
|
297
|
-
var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
|
|
40
|
+
// src/util/dynamic-table.ts
|
|
41
|
+
import { Filter, JsonSchema, Obj, Order, Query, Ref, Type } from "@dxos/echo";
|
|
42
|
+
import { ProjectionModel, ViewModel, createEchoChangeCallback as createEchoChangeCallback2, getSchemaFromPropertyDefinitions } from "@dxos/schema";
|
|
43
|
+
var getBaseSchema = ({ schema, typename, properties, jsonSchema }) => {
|
|
298
44
|
if (typename && properties) {
|
|
299
45
|
const schema2 = getSchemaFromPropertyDefinitions(typename, properties);
|
|
300
46
|
return {
|
|
301
47
|
typename: schema2.typename,
|
|
302
|
-
jsonSchema: schema2
|
|
48
|
+
jsonSchema: JsonSchema.toJsonSchema(schema2)
|
|
303
49
|
};
|
|
304
50
|
} else if (schema) {
|
|
305
51
|
return {
|
|
306
|
-
typename: getTypename(schema),
|
|
307
|
-
jsonSchema: toJsonSchema(schema)
|
|
52
|
+
typename: Type.getTypename(schema),
|
|
53
|
+
jsonSchema: JsonSchema.toJsonSchema(schema)
|
|
308
54
|
};
|
|
309
55
|
} else if (typename && jsonSchema) {
|
|
310
56
|
return {
|
|
@@ -315,34 +61,41 @@ var getBaseSchema = ({ typename, properties, jsonSchema, schema }) => {
|
|
|
315
61
|
throw new Error("invalid properties");
|
|
316
62
|
}
|
|
317
63
|
};
|
|
318
|
-
var makeDynamicTable = ({
|
|
319
|
-
const view =
|
|
320
|
-
|
|
321
|
-
typename,
|
|
64
|
+
var makeDynamicTable = ({ registry, jsonSchema, properties }) => {
|
|
65
|
+
const view = ViewModel.make({
|
|
66
|
+
query: Query.select(Filter.everything()),
|
|
322
67
|
jsonSchema,
|
|
323
68
|
...properties && {
|
|
324
69
|
fields: properties.map((property) => property.name)
|
|
325
70
|
}
|
|
326
71
|
});
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
72
|
+
const object = Obj.make(Table_exports.Table, {
|
|
73
|
+
view: Ref.make(view),
|
|
74
|
+
sizes: {}
|
|
75
|
+
});
|
|
76
|
+
const projection = new ProjectionModel({
|
|
77
|
+
registry,
|
|
78
|
+
view,
|
|
79
|
+
baseSchema: jsonSchema,
|
|
80
|
+
change: createEchoChangeCallback2(view, jsonSchema)
|
|
330
81
|
});
|
|
331
|
-
|
|
332
|
-
if (properties &&
|
|
333
|
-
setProperties(view, projection, properties);
|
|
82
|
+
projection.normalizeView();
|
|
83
|
+
if (properties && projection.getFields()) {
|
|
84
|
+
setProperties(view, projection, object, properties);
|
|
334
85
|
}
|
|
335
86
|
return {
|
|
336
|
-
|
|
337
|
-
|
|
87
|
+
projection,
|
|
88
|
+
object
|
|
338
89
|
};
|
|
339
90
|
};
|
|
340
|
-
var setProperties = (view, projection, properties) => {
|
|
91
|
+
var setProperties = (view, projection, table, properties) => {
|
|
341
92
|
for (const property of properties) {
|
|
342
|
-
const field =
|
|
93
|
+
const field = projection.getFields().find((field2) => field2.path === property.name);
|
|
343
94
|
if (field) {
|
|
344
95
|
if (property.size !== void 0) {
|
|
345
|
-
|
|
96
|
+
Obj.update(table, (table2) => {
|
|
97
|
+
table2.sizes[field.path] = property.size;
|
|
98
|
+
});
|
|
346
99
|
}
|
|
347
100
|
if (property.title !== void 0) {
|
|
348
101
|
const fieldProjection = projection.getFieldProjection(field.id);
|
|
@@ -355,1807 +108,502 @@ var setProperties = (view, projection, properties) => {
|
|
|
355
108
|
});
|
|
356
109
|
}
|
|
357
110
|
if (property.sort) {
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
364
|
-
];
|
|
111
|
+
const currentQuery = Query.fromAst(Obj.getSnapshot(view).query.ast);
|
|
112
|
+
const newQuery = currentQuery.orderBy(Order.property(field.path, property.sort));
|
|
113
|
+
Obj.update(view, (view2) => {
|
|
114
|
+
view2.query.ast = newQuery.ast;
|
|
115
|
+
});
|
|
365
116
|
}
|
|
366
117
|
}
|
|
367
118
|
}
|
|
368
119
|
};
|
|
369
120
|
|
|
370
|
-
//
|
|
121
|
+
// src/util/signals.ts
|
|
371
122
|
var touch = (value) => value;
|
|
372
123
|
|
|
373
|
-
//
|
|
374
|
-
import
|
|
375
|
-
import
|
|
376
|
-
import { PublicKey } from "@dxos/react-client";
|
|
377
|
-
import { live as live2 } from "@dxos/react-client/echo";
|
|
378
|
-
import { createFieldId, createView as createView2, getSchemaProperties, ViewProjection as ViewProjection2 } from "@dxos/schema";
|
|
379
|
-
var initializeTable = async ({ client, space, table, typename, initialRow = true }) => {
|
|
380
|
-
if (typename) {
|
|
381
|
-
const schema = await space.db.graph.getSchemaByTypename(typename, space.db);
|
|
382
|
-
if (!schema) {
|
|
383
|
-
throw new Error(`Schema not found: ${typename}`);
|
|
384
|
-
}
|
|
385
|
-
const fields = getSchemaProperties(schema.ast).map((prop) => prop.name);
|
|
386
|
-
table.view = Ref2.make(createView2({
|
|
387
|
-
// TODO(ZaymonFC): Don't hardcode name?
|
|
388
|
-
name: "View",
|
|
389
|
-
typename: schema.typename,
|
|
390
|
-
jsonSchema: schema.jsonSchema,
|
|
391
|
-
fields
|
|
392
|
-
}));
|
|
393
|
-
return schema;
|
|
394
|
-
} else {
|
|
395
|
-
const [schema] = await space.db.schemaRegistry.register([
|
|
396
|
-
createContactSchema()
|
|
397
|
-
]);
|
|
398
|
-
const fields = ContactFields;
|
|
399
|
-
table.view = Ref2.make(createView2({
|
|
400
|
-
name: "View",
|
|
401
|
-
typename: schema.typename,
|
|
402
|
-
jsonSchema: schema.jsonSchema,
|
|
403
|
-
fields
|
|
404
|
-
}));
|
|
405
|
-
createProjection(schema, table.view.target);
|
|
406
|
-
if (initialRow) {
|
|
407
|
-
space.db.add(live2(schema, {}));
|
|
408
|
-
}
|
|
409
|
-
return schema;
|
|
410
|
-
}
|
|
411
|
-
};
|
|
412
|
-
var createContactSchema = () => TypedObject({
|
|
413
|
-
typename: `example.com/type/${PublicKey.random().truncate()}`,
|
|
414
|
-
version: "0.1.0"
|
|
415
|
-
})({
|
|
416
|
-
name: Schema2.optional(Schema2.String).annotations({
|
|
417
|
-
title: "Name"
|
|
418
|
-
}),
|
|
419
|
-
active: Schema2.optional(Schema2.Boolean).annotations({
|
|
420
|
-
title: "Active"
|
|
421
|
-
}),
|
|
422
|
-
email: Schema2.optional(Format.Email),
|
|
423
|
-
salary: Schema2.optional(Format.Currency()).annotations({
|
|
424
|
-
title: "Salary"
|
|
425
|
-
})
|
|
426
|
-
});
|
|
427
|
-
var ContactFields = [
|
|
428
|
-
"name",
|
|
429
|
-
"email",
|
|
430
|
-
"salary",
|
|
431
|
-
"active"
|
|
432
|
-
];
|
|
433
|
-
var createProjection = (schema, view) => {
|
|
434
|
-
const projection = new ViewProjection2(schema.jsonSchema, view);
|
|
435
|
-
projection.setFieldProjection({
|
|
436
|
-
field: {
|
|
437
|
-
id: view.fields.find((f) => f.path === "salary").id,
|
|
438
|
-
path: "salary",
|
|
439
|
-
size: 150
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
projection.setFieldProjection({
|
|
443
|
-
field: {
|
|
444
|
-
id: view.fields.find((f) => f.path === "active").id,
|
|
445
|
-
path: "active",
|
|
446
|
-
size: 100
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
projection.setFieldProjection({
|
|
450
|
-
field: {
|
|
451
|
-
id: createFieldId(),
|
|
452
|
-
path: "manager",
|
|
453
|
-
referencePath: "name"
|
|
454
|
-
},
|
|
455
|
-
props: {
|
|
456
|
-
property: "manager",
|
|
457
|
-
type: TypeEnum.Ref,
|
|
458
|
-
format: FormatEnum.Ref,
|
|
459
|
-
referenceSchema: schema.typename,
|
|
460
|
-
title: "Manager"
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
return projection;
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
// packages/ui/react-ui-table/src/util/table-buttons.ts
|
|
467
|
-
var BUTTON_IDENTIFIERS = {
|
|
468
|
-
columnSettings: "data-table-column-settings-button",
|
|
469
|
-
newColumn: "data-table-new-column-button",
|
|
470
|
-
referencedCell: "data-table-ref-cell-button",
|
|
471
|
-
rowMenu: "data-table-row-menu-button",
|
|
472
|
-
sort: "data-table-sort-button"
|
|
473
|
-
};
|
|
474
|
-
var createButton = ({ attr, data, disabled = false, icon, testId, type = "primary" }) => {
|
|
475
|
-
const dataAttrs = Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
476
|
-
const positionClass = type === "primary" ? "inline-end-2" : "inline-end-9";
|
|
477
|
-
return `<button ${attr} data-testid="${testId}" class="dx-button is-6 pli-0.5 min-bs-0 absolute inset-block-1 ${positionClass}" ${dataAttrs} ${disabled ? "disabled" : ""}><svg data-size="4"><use href="/icons.svg#${icon}"/></svg></button>`;
|
|
478
|
-
};
|
|
479
|
-
var addColumnButton = {
|
|
480
|
-
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
481
|
-
icon: "ph--plus--regular",
|
|
482
|
-
render: ({ disabled }) => {
|
|
483
|
-
return createButton({
|
|
484
|
-
attr: BUTTON_IDENTIFIERS.newColumn,
|
|
485
|
-
icon: addColumnButton.icon,
|
|
486
|
-
disabled,
|
|
487
|
-
data: {},
|
|
488
|
-
testId: "table-new-column-button"
|
|
489
|
-
});
|
|
490
|
-
},
|
|
491
|
-
getData: (_el) => ({
|
|
492
|
-
type: "newColumn"
|
|
493
|
-
})
|
|
494
|
-
};
|
|
495
|
-
var columnSettingsButton = {
|
|
496
|
-
attr: BUTTON_IDENTIFIERS.columnSettings,
|
|
497
|
-
icon: "ph--caret-down--regular",
|
|
498
|
-
render: ({ fieldId }) => {
|
|
499
|
-
return createButton({
|
|
500
|
-
attr: BUTTON_IDENTIFIERS.columnSettings,
|
|
501
|
-
icon: columnSettingsButton.icon,
|
|
502
|
-
data: {
|
|
503
|
-
"data-field-id": fieldId
|
|
504
|
-
},
|
|
505
|
-
testId: "table-column-settings-button"
|
|
506
|
-
});
|
|
507
|
-
},
|
|
508
|
-
getData: (el) => ({
|
|
509
|
-
type: "columnSettings",
|
|
510
|
-
fieldId: el.getAttribute("data-field-id")
|
|
511
|
-
})
|
|
512
|
-
};
|
|
513
|
-
var rowMenuButton = {
|
|
514
|
-
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
515
|
-
icon: "ph--dots-three--regular",
|
|
516
|
-
render: ({ rowIndex }) => {
|
|
517
|
-
return createButton({
|
|
518
|
-
attr: BUTTON_IDENTIFIERS.rowMenu,
|
|
519
|
-
icon: rowMenuButton.icon,
|
|
520
|
-
data: {
|
|
521
|
-
"data-row-index": rowIndex.toString()
|
|
522
|
-
},
|
|
523
|
-
testId: "table-row-menu-button"
|
|
524
|
-
});
|
|
525
|
-
},
|
|
526
|
-
getData: (el) => ({
|
|
527
|
-
type: "rowMenu",
|
|
528
|
-
rowIndex: Number(el.getAttribute("data-row-index"))
|
|
529
|
-
})
|
|
530
|
-
};
|
|
531
|
-
var sortButton = {
|
|
532
|
-
attr: BUTTON_IDENTIFIERS.sort,
|
|
533
|
-
icon: "ph--sort-ascending--regular",
|
|
534
|
-
render: ({ fieldId, direction }) => {
|
|
535
|
-
return createButton({
|
|
536
|
-
attr: BUTTON_IDENTIFIERS.sort,
|
|
537
|
-
icon: direction === "desc" ? "ph--sort-descending--regular" : "ph--sort-ascending--regular",
|
|
538
|
-
data: {
|
|
539
|
-
"data-field-id": fieldId,
|
|
540
|
-
"data-direction": direction ?? ""
|
|
541
|
-
},
|
|
542
|
-
testId: "table-sort-button",
|
|
543
|
-
// TODO(ZaymonFC): All buttons should be rendered into an absolutely positioned flex container.
|
|
544
|
-
// This is a bit hacky.
|
|
545
|
-
type: "secondary"
|
|
546
|
-
});
|
|
547
|
-
},
|
|
548
|
-
getData: (el) => ({
|
|
549
|
-
type: "sort",
|
|
550
|
-
fieldId: el.getAttribute("data-field-id"),
|
|
551
|
-
direction: el.getAttribute("data-direction")
|
|
552
|
-
})
|
|
553
|
-
};
|
|
554
|
-
var tableButtons = {
|
|
555
|
-
addColumn: addColumnButton,
|
|
556
|
-
columnSettings: columnSettingsButton,
|
|
557
|
-
rowMenu: rowMenuButton,
|
|
558
|
-
sort: sortButton
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// packages/ui/react-ui-table/src/util/table-controls.ts
|
|
562
|
-
var CONTROL_IDENTIFIERS = {
|
|
563
|
-
checkbox: "data-table-checkbox",
|
|
564
|
-
switch: "data-table-switch"
|
|
565
|
-
};
|
|
566
|
-
var BASE_CLASSES = {
|
|
567
|
-
checkbox: "absolute inset-block-[.375rem] inline-end-[.375rem] dx-checkbox",
|
|
568
|
-
switch: "absolute inset-block-[.25rem] inline-end-[.25rem] dx-checkbox--switch"
|
|
569
|
-
};
|
|
570
|
-
var renderAttributes = (data) => {
|
|
571
|
-
return Object.entries(data).map(([k, v]) => `${k}="${v}"`).join(" ");
|
|
572
|
-
};
|
|
573
|
-
var renderInput = (baseClass, attrs, checked = false, disabled = false, preventToggle = false, testId) => {
|
|
574
|
-
return `<input type="checkbox" class="${baseClass}" ${renderAttributes(attrs)} ${checked ? "checked" : ""} ${preventToggle ? 'onclick="return false"' : ""} ${disabled ? "disabled" : ""} data-testid="${testId}"/>`;
|
|
575
|
-
};
|
|
576
|
-
var CheckboxStory = ({ rowIndex, header = false, checked = false, disabled = false }) => {
|
|
577
|
-
const attrs = {
|
|
578
|
-
[CONTROL_IDENTIFIERS.checkbox]: "",
|
|
579
|
-
"data-row-index": rowIndex.toString(),
|
|
580
|
-
...header && {
|
|
581
|
-
"data-header": ""
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
return renderInput(BASE_CLASSES.checkbox, attrs, checked, disabled, true, "table-selection");
|
|
585
|
-
};
|
|
586
|
-
var SwitchStory = ({ colIndex, rowIndex, checked = false, disabled = false }) => {
|
|
587
|
-
const attrs = {
|
|
588
|
-
[CONTROL_IDENTIFIERS.switch]: "",
|
|
589
|
-
"data-row-index": rowIndex.toString(),
|
|
590
|
-
"data-col-index": colIndex.toString()
|
|
591
|
-
};
|
|
592
|
-
return renderInput(BASE_CLASSES.switch, attrs, checked, disabled, true, "table-switch");
|
|
593
|
-
};
|
|
594
|
-
var tableControls = {
|
|
595
|
-
checkbox: {
|
|
596
|
-
attr: CONTROL_IDENTIFIERS.checkbox,
|
|
597
|
-
render: CheckboxStory,
|
|
598
|
-
getData: (el) => ({
|
|
599
|
-
type: "checkbox",
|
|
600
|
-
rowIndex: Number(el.getAttribute("data-row-index")),
|
|
601
|
-
header: el.hasAttribute("data-header")
|
|
602
|
-
})
|
|
603
|
-
},
|
|
604
|
-
switch: {
|
|
605
|
-
attr: CONTROL_IDENTIFIERS.switch,
|
|
606
|
-
render: SwitchStory,
|
|
607
|
-
getData: (el) => ({
|
|
608
|
-
type: "switch",
|
|
609
|
-
rowIndex: Number(el.getAttribute("data-row-index")),
|
|
610
|
-
colIndex: Number(el.getAttribute("data-col-index"))
|
|
611
|
-
})
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
// packages/ui/react-ui-table/src/util/schema.ts
|
|
616
|
-
import { Schema as Schema3 } from "effect";
|
|
617
|
-
import { isTypeLiteral, TypeLiteral } from "effect/SchemaAST";
|
|
124
|
+
// src/util/schema.ts
|
|
125
|
+
import * as Schema from "effect/Schema";
|
|
126
|
+
import * as SchemaAST from "effect/SchemaAST";
|
|
618
127
|
var narrowSchema = (schema, paths) => {
|
|
619
128
|
const ast = schema?.ast;
|
|
620
|
-
if (isTypeLiteral(ast)) {
|
|
129
|
+
if (SchemaAST.isTypeLiteral(ast)) {
|
|
621
130
|
const propertySignatures = ast.propertySignatures.filter((signature) => paths.includes(signature.name.toString()));
|
|
622
131
|
if (propertySignatures.length > 0) {
|
|
623
|
-
const narrowType = new TypeLiteral(propertySignatures, []);
|
|
624
|
-
return
|
|
132
|
+
const narrowType = new SchemaAST.TypeLiteral(propertySignatures, []);
|
|
133
|
+
return Schema.make(narrowType);
|
|
625
134
|
}
|
|
626
135
|
}
|
|
627
136
|
return void 0;
|
|
628
137
|
};
|
|
629
138
|
|
|
630
|
-
//
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}), this._hasSelection = computed(() => this._validSelectedIds.value.size > 0), this._allSelected = computed(() => {
|
|
643
|
-
const rows = this._rows.value;
|
|
644
|
-
if (rows.length === 0) {
|
|
645
|
-
return false;
|
|
646
|
-
}
|
|
647
|
-
return rows.every((row) => this._selection.value.has(row.id));
|
|
648
|
-
}), this.getSelectedRows = () => {
|
|
649
|
-
const selectedIds = this._validSelectedIds.value;
|
|
650
|
-
return this._rows.value.filter((row) => selectedIds.has(row.id));
|
|
651
|
-
}, this.isRowIndexSelected = (rowIndex) => {
|
|
652
|
-
const row = this._rows.value[rowIndex];
|
|
653
|
-
return this._selection.value.has(row.id);
|
|
654
|
-
}, this.isObjectSelected = (object) => {
|
|
655
|
-
return this._selection.value.has(object.id);
|
|
656
|
-
}, this.toggleSelectionForRowIndex = (rowIndex) => {
|
|
657
|
-
const row = this._rows.value[rowIndex];
|
|
658
|
-
const newSelection = new Set(this._selection.value);
|
|
659
|
-
if (newSelection.has(row.id)) {
|
|
660
|
-
newSelection.delete(row.id);
|
|
661
|
-
} else {
|
|
662
|
-
if (this._selectionMode === "single") {
|
|
663
|
-
newSelection.clear();
|
|
664
|
-
}
|
|
665
|
-
newSelection.add(row.id);
|
|
666
|
-
}
|
|
667
|
-
this._selection.value = newSelection;
|
|
668
|
-
}, this.setSelection = (mode) => {
|
|
669
|
-
switch (mode) {
|
|
670
|
-
case "all": {
|
|
671
|
-
this._selection.value = new Set(this._rows.value.map((row) => row.id));
|
|
672
|
-
break;
|
|
673
|
-
}
|
|
674
|
-
case "none": {
|
|
675
|
-
this._selection.value = /* @__PURE__ */ new Set();
|
|
676
|
-
break;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
async _open() {
|
|
682
|
-
const selectionWatcher = effect(() => {
|
|
683
|
-
touch(this._selection.value);
|
|
684
|
-
this._onSelectionChanged?.();
|
|
139
|
+
// src/model/modal-controller.ts
|
|
140
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
141
|
+
var ModalController = class {
|
|
142
|
+
_registry;
|
|
143
|
+
_state;
|
|
144
|
+
_triggerRef = {
|
|
145
|
+
current: null
|
|
146
|
+
};
|
|
147
|
+
constructor(registry) {
|
|
148
|
+
this._registry = registry;
|
|
149
|
+
this._state = Atom.make({
|
|
150
|
+
type: "closed"
|
|
685
151
|
});
|
|
686
|
-
this._ctx.onDispose(selectionWatcher);
|
|
687
|
-
}
|
|
688
|
-
//
|
|
689
|
-
// Getters
|
|
690
|
-
//
|
|
691
|
-
get selection() {
|
|
692
|
-
return this._selection;
|
|
693
152
|
}
|
|
694
|
-
get
|
|
695
|
-
return this.
|
|
153
|
+
get state() {
|
|
154
|
+
return this._state;
|
|
696
155
|
}
|
|
697
|
-
get
|
|
698
|
-
return this.
|
|
156
|
+
get stateValue() {
|
|
157
|
+
return this._registry.get(this._state);
|
|
699
158
|
}
|
|
700
|
-
get
|
|
701
|
-
return this.
|
|
159
|
+
get trigger() {
|
|
160
|
+
return this._triggerRef;
|
|
702
161
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
this.
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
if (local?.type === "active") {
|
|
724
|
-
if (!viewSort) {
|
|
725
|
-
return true;
|
|
726
|
-
}
|
|
727
|
-
return local.sort.fieldId !== viewSort.fieldId || local.sort.direction !== viewSort.direction;
|
|
162
|
+
setTrigger = (trigger) => {
|
|
163
|
+
this._triggerRef.current = trigger;
|
|
164
|
+
};
|
|
165
|
+
showRowMenu = (rowIndex) => {
|
|
166
|
+
this._registry.set(this._state, {
|
|
167
|
+
type: "row",
|
|
168
|
+
rowIndex
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
showColumnMenu = (fieldId) => {
|
|
172
|
+
this._registry.set(this._state, {
|
|
173
|
+
type: "column",
|
|
174
|
+
fieldId
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
showColumnCreator = () => {
|
|
178
|
+
this._registry.set(this._state, {
|
|
179
|
+
type: "columnSettings",
|
|
180
|
+
mode: {
|
|
181
|
+
type: "create"
|
|
728
182
|
}
|
|
729
|
-
return false;
|
|
730
183
|
});
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
184
|
+
};
|
|
185
|
+
showReferencePanel = (targetId, schemaId) => {
|
|
186
|
+
this._registry.set(this._state, {
|
|
187
|
+
type: "refPanel",
|
|
188
|
+
targetId,
|
|
189
|
+
typename: schemaId
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
openColumnSettings = () => {
|
|
193
|
+
const currentState = this._registry.get(this._state);
|
|
194
|
+
if (currentState.type === "column") {
|
|
195
|
+
const fieldId = currentState.fieldId;
|
|
196
|
+
requestAnimationFrame(() => {
|
|
197
|
+
this._registry.set(this._state, {
|
|
198
|
+
type: "columnSettings",
|
|
199
|
+
mode: {
|
|
200
|
+
type: "edit",
|
|
201
|
+
fieldId
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
741
205
|
}
|
|
742
|
-
|
|
743
|
-
|
|
206
|
+
};
|
|
207
|
+
close = () => {
|
|
208
|
+
this._registry.set(this._state, {
|
|
209
|
+
type: "closed"
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// src/components/TableCellEditor/TableCellEditor.tsx
|
|
215
|
+
import { EditorView } from "@codemirror/view";
|
|
216
|
+
import React3, { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
217
|
+
import { debounce } from "@dxos/async";
|
|
218
|
+
import { Format, TypeEnum } from "@dxos/echo/internal";
|
|
219
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
220
|
+
import { GridCellEditor, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
|
|
221
|
+
|
|
222
|
+
// src/components/TableCellEditor/CellValidationMessage.tsx
|
|
223
|
+
import React from "react";
|
|
224
|
+
import { useGridContext } from "@dxos/react-ui-grid";
|
|
225
|
+
var CellValidationMessage = ({ __gridScope, validationError, variant = "error" }) => {
|
|
226
|
+
const { editing, editBox: box } = useGridContext("GridSheetCellEditor", __gridScope);
|
|
227
|
+
if (!editing || !validationError) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const bgClass = variant === "error" ? "bg-error-surface" : "bg-warning-surface";
|
|
231
|
+
const textClass = variant === "error" ? "text-error-surface-text" : "text-warning-surface-text";
|
|
232
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
233
|
+
role: "none",
|
|
234
|
+
className: `absolute ${bgClass} ${textClass} rounded-h-sm text-xs p-1`,
|
|
235
|
+
style: {
|
|
236
|
+
...{
|
|
237
|
+
"--dx-grid-cell-width": `${box?.inlineSize ?? 200}px`
|
|
238
|
+
},
|
|
239
|
+
zIndex: 10,
|
|
240
|
+
insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
|
|
241
|
+
insetInlineStart: box.insetInlineStart,
|
|
242
|
+
inlineSize: box.inlineSize
|
|
744
243
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
};
|
|
244
|
+
}, validationError);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// src/components/TableCellEditor/FormCellEditor.tsx
|
|
248
|
+
import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
249
|
+
import { Entity } from "@dxos/echo";
|
|
250
|
+
import { Ref as Ref2, getValue } from "@dxos/echo/internal";
|
|
251
|
+
import { invariant } from "@dxos/invariant";
|
|
252
|
+
import { Popover } from "@dxos/react-ui";
|
|
253
|
+
import { Form } from "@dxos/react-ui-form";
|
|
254
|
+
import { parseCellIndex, useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
|
|
255
|
+
import { getDeep, isTruthy, setDeep } from "@dxos/util";
|
|
256
|
+
import { translationKey } from "#translations";
|
|
257
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
|
|
258
|
+
var createOptionLabel = [
|
|
259
|
+
"create-new-object.label",
|
|
260
|
+
{
|
|
261
|
+
ns: translationKey
|
|
765
262
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
263
|
+
];
|
|
264
|
+
var FormCellEditor = ({ __gridScope, schema, model, fieldProjection, onSave, onCreate, ...formProps }) => {
|
|
265
|
+
const anchorRef = useRef(null);
|
|
266
|
+
const { id: _gridId, editing: contextEditing, setEditing } = useGridContext2("ArrayEditor", __gridScope);
|
|
267
|
+
const [editing, setLocalEditing] = useState(false);
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (contextEditing && contextEditing.cellElement) {
|
|
270
|
+
anchorRef.current = contextEditing.cellElement.querySelector(".dx-grid__cell__content");
|
|
271
|
+
setLocalEditing(true);
|
|
272
|
+
} else {
|
|
273
|
+
anchorRef.current = null;
|
|
274
|
+
setLocalEditing(false);
|
|
769
275
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
this.setSort(fieldId, "asc");
|
|
777
|
-
break;
|
|
778
|
-
}
|
|
276
|
+
}, [
|
|
277
|
+
contextEditing
|
|
278
|
+
]);
|
|
279
|
+
const narrowedSchema = useMemo(() => {
|
|
280
|
+
if (!schema) {
|
|
281
|
+
return void 0;
|
|
779
282
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
];
|
|
283
|
+
return narrowSchema(schema, [
|
|
284
|
+
fieldProjection.field.path
|
|
285
|
+
]);
|
|
286
|
+
}, [
|
|
287
|
+
JSON.stringify(schema),
|
|
288
|
+
fieldProjection.field.path
|
|
289
|
+
]);
|
|
290
|
+
const originalRow = useMemo(() => {
|
|
291
|
+
if (model && contextEditing) {
|
|
292
|
+
const cell = parseCellIndex(contextEditing.index);
|
|
293
|
+
if (model.isDraftCell(cell)) {
|
|
294
|
+
const draftRow = model.getDraftRows()[cell.row];
|
|
295
|
+
invariant(draftRow, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 52, S: void 0, A: ["draftRow", ""] });
|
|
296
|
+
return draftRow.data;
|
|
792
297
|
} else {
|
|
793
|
-
|
|
298
|
+
const row = model.getRowAt(cell.row);
|
|
299
|
+
invariant(row, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0, A: ["row", ""] });
|
|
300
|
+
return row;
|
|
794
301
|
}
|
|
795
|
-
this._localSort.value = void 0;
|
|
796
302
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const dataWithIndices = this._rows.value.map((item, index) => {
|
|
814
|
-
const sortValue = this.getSortValue(props, field, item);
|
|
815
|
-
const isEmpty = !(props.type === TypeEnum2.Boolean) && (sortValue == null || sortValue === "");
|
|
816
|
-
return {
|
|
817
|
-
item,
|
|
818
|
-
index,
|
|
819
|
-
value: sortValue,
|
|
820
|
-
isEmpty
|
|
821
|
-
};
|
|
822
|
-
});
|
|
823
|
-
const ordered = orderBy(dataWithIndices, [
|
|
824
|
-
"isEmpty",
|
|
825
|
-
"value"
|
|
826
|
-
], [
|
|
827
|
-
"asc",
|
|
828
|
-
sort.direction
|
|
829
|
-
]);
|
|
830
|
-
ordered.forEach(({ index: dataIndex }, displayIndex) => {
|
|
831
|
-
if (displayIndex !== dataIndex) {
|
|
832
|
-
this._displayToDataIndex.set(displayIndex, dataIndex);
|
|
833
|
-
}
|
|
834
|
-
});
|
|
835
|
-
return ordered.map(({ item }) => item);
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
getSortValue(props, field, item) {
|
|
839
|
-
const { type, format } = props;
|
|
840
|
-
const value = getValue(item, field.path);
|
|
841
|
-
if (type === TypeEnum2.Boolean) {
|
|
842
|
-
return !!value;
|
|
303
|
+
return void 0;
|
|
304
|
+
}, [
|
|
305
|
+
model,
|
|
306
|
+
contextEditing
|
|
307
|
+
]);
|
|
308
|
+
const initialFormValues = useMemo(() => originalRow ? JSON.parse(JSON.stringify(originalRow)) : {}, [
|
|
309
|
+
originalRow
|
|
310
|
+
]);
|
|
311
|
+
const [formValues, setFormValues] = useState(initialFormValues);
|
|
312
|
+
const handleValuesChanged = useCallback((values) => {
|
|
313
|
+
setFormValues(values);
|
|
314
|
+
}, []);
|
|
315
|
+
const handleOpenChange = useCallback((nextOpen) => {
|
|
316
|
+
if (nextOpen === false) {
|
|
317
|
+
setEditing(null);
|
|
318
|
+
onSave?.();
|
|
843
319
|
}
|
|
844
|
-
|
|
845
|
-
|
|
320
|
+
setLocalEditing(nextOpen);
|
|
321
|
+
}, []);
|
|
322
|
+
const handleSave = useCallback((values) => {
|
|
323
|
+
if (!originalRow) {
|
|
324
|
+
return;
|
|
846
325
|
}
|
|
847
|
-
|
|
848
|
-
|
|
326
|
+
const path = fieldProjection.field.path;
|
|
327
|
+
const value = getDeep(values, [
|
|
328
|
+
path
|
|
329
|
+
]);
|
|
330
|
+
if (model) {
|
|
331
|
+
model.changeRow(originalRow, (mutableRow) => {
|
|
332
|
+
setDeep(mutableRow, [
|
|
333
|
+
path
|
|
334
|
+
], value);
|
|
335
|
+
});
|
|
336
|
+
} else {
|
|
337
|
+
setDeep(originalRow, [
|
|
338
|
+
path
|
|
339
|
+
], value);
|
|
849
340
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
341
|
+
contextEditing?.cellElement?.focus();
|
|
342
|
+
setEditing(null);
|
|
343
|
+
setLocalEditing(false);
|
|
344
|
+
onSave?.();
|
|
345
|
+
}, [
|
|
346
|
+
fieldProjection.field.path,
|
|
347
|
+
onSave,
|
|
348
|
+
contextEditing,
|
|
349
|
+
originalRow,
|
|
350
|
+
model
|
|
351
|
+
]);
|
|
352
|
+
const handleCreate = useCallback((schema2, values) => {
|
|
353
|
+
const objectWithId = onCreate?.(schema2, values);
|
|
354
|
+
if (objectWithId && originalRow) {
|
|
355
|
+
const ref = Ref2.make(objectWithId);
|
|
356
|
+
const path = fieldProjection.field.path;
|
|
357
|
+
if (model) {
|
|
358
|
+
model.changeRow(originalRow, (mutableRow) => {
|
|
359
|
+
setDeep(mutableRow, [
|
|
360
|
+
path
|
|
361
|
+
], ref);
|
|
362
|
+
});
|
|
363
|
+
} else {
|
|
364
|
+
setDeep(originalRow, [
|
|
365
|
+
path
|
|
366
|
+
], ref);
|
|
854
367
|
}
|
|
855
|
-
const option = options.find((option2) => option2.id === value);
|
|
856
|
-
return option ? options.indexOf(option) : void 0;
|
|
857
|
-
}
|
|
858
|
-
if (format === FormatEnum2.Ref && field.referencePath) {
|
|
859
|
-
const refValue = getValue(value.target, field.referencePath);
|
|
860
|
-
return refValue;
|
|
861
368
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
369
|
+
contextEditing?.cellElement?.focus();
|
|
370
|
+
setEditing(null);
|
|
371
|
+
setLocalEditing(false);
|
|
372
|
+
onSave?.();
|
|
373
|
+
}, [
|
|
374
|
+
fieldProjection.field.path,
|
|
375
|
+
onSave,
|
|
376
|
+
contextEditing,
|
|
377
|
+
originalRow,
|
|
378
|
+
onCreate,
|
|
379
|
+
model
|
|
380
|
+
]);
|
|
381
|
+
const getOptions = useCallback((results) => results.map((obj) => {
|
|
382
|
+
return {
|
|
383
|
+
id: Entity.getDXN(obj).toString(),
|
|
384
|
+
label: getValue(obj, fieldProjection.field.referencePath) || obj.id.toString()
|
|
385
|
+
};
|
|
386
|
+
}).filter(isTruthy), [
|
|
387
|
+
fieldProjection
|
|
388
|
+
]);
|
|
389
|
+
if (!editing) {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
return /* @__PURE__ */ React2.createElement(Popover.Root, {
|
|
393
|
+
open: editing,
|
|
394
|
+
onOpenChange: handleOpenChange
|
|
395
|
+
}, /* @__PURE__ */ React2.createElement(Popover.VirtualTrigger, {
|
|
396
|
+
virtualRef: anchorRef
|
|
397
|
+
}), /* @__PURE__ */ React2.createElement(Popover.Portal, null, /* @__PURE__ */ React2.createElement(Popover.Content, {
|
|
398
|
+
tabIndex: -1,
|
|
399
|
+
classNames: "dx-card-popover-width dx-density-fine"
|
|
400
|
+
}, /* @__PURE__ */ React2.createElement(Popover.Arrow, null), /* @__PURE__ */ React2.createElement(Popover.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Root, {
|
|
401
|
+
...formProps,
|
|
402
|
+
autoFocus: true,
|
|
403
|
+
schema: narrowedSchema,
|
|
404
|
+
values: formValues,
|
|
405
|
+
onValuesChanged: handleValuesChanged,
|
|
406
|
+
projection: model?.projection,
|
|
407
|
+
createInitialValuePath: fieldProjection.field.referencePath,
|
|
408
|
+
createOptionIcon: "ph--plus--regular",
|
|
409
|
+
createOptionLabel,
|
|
410
|
+
db: model?.db,
|
|
411
|
+
getOptions,
|
|
412
|
+
onCreate: handleCreate,
|
|
413
|
+
onSave: handleSave
|
|
414
|
+
}, /* @__PURE__ */ React2.createElement(Form.Viewport, null, /* @__PURE__ */ React2.createElement(Form.Content, null, /* @__PURE__ */ React2.createElement(Form.FieldSet, null), /* @__PURE__ */ React2.createElement(Form.Actions, null))))))));
|
|
868
415
|
};
|
|
869
416
|
|
|
870
|
-
//
|
|
871
|
-
var
|
|
872
|
-
var
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
let match;
|
|
878
|
-
while ((match = TAG_PATTERN_REGEX.exec(value)) !== null) {
|
|
879
|
-
if (match[2]) {
|
|
880
|
-
ids.push(match[2]);
|
|
417
|
+
// src/components/TableCellEditor/TableCellEditor.tsx
|
|
418
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
|
|
419
|
+
var TableValueEditor = ({ __gridScope, schema, model, modals, onFocus, onSave, onCreate }) => {
|
|
420
|
+
const { editing } = useGridContext3("TableValueEditor", __gridScope);
|
|
421
|
+
const fieldProjection = useMemo2(() => {
|
|
422
|
+
if (!model || !editing) {
|
|
423
|
+
return;
|
|
881
424
|
}
|
|
425
|
+
const { col } = parseCellIndex2(editing.index);
|
|
426
|
+
const field = model.projection.getFields()[col];
|
|
427
|
+
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
428
|
+
invariant2(fieldProjection2, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 21, S: void 0, A: ["fieldProjection", ""] });
|
|
429
|
+
return fieldProjection2;
|
|
430
|
+
}, [
|
|
431
|
+
model,
|
|
432
|
+
editing
|
|
433
|
+
]);
|
|
434
|
+
if (fieldProjection?.props.type === TypeEnum.Array || fieldProjection?.props.format === Format.TypeFormat.SingleSelect || fieldProjection?.props.format === Format.TypeFormat.Ref) {
|
|
435
|
+
return /* @__PURE__ */ React3.createElement(FormCellEditor, {
|
|
436
|
+
__gridScope,
|
|
437
|
+
schema,
|
|
438
|
+
model,
|
|
439
|
+
fieldProjection,
|
|
440
|
+
modals,
|
|
441
|
+
onSave,
|
|
442
|
+
onCreate
|
|
443
|
+
});
|
|
882
444
|
}
|
|
883
|
-
return
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
enabled: true,
|
|
891
|
-
mode: "multiple"
|
|
892
|
-
},
|
|
893
|
-
dataEditable: false,
|
|
894
|
-
schemaEditable: false
|
|
445
|
+
return /* @__PURE__ */ React3.createElement(TableCellEditor, {
|
|
446
|
+
model,
|
|
447
|
+
modals,
|
|
448
|
+
onFocus,
|
|
449
|
+
onSave,
|
|
450
|
+
__gridScope
|
|
451
|
+
});
|
|
895
452
|
};
|
|
896
|
-
var
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
453
|
+
var TableCellEditor = ({ __gridScope, model, modals, onFocus, onSave }) => {
|
|
454
|
+
const { editing, setEditing } = useGridContext3("TableCellEditor", __gridScope);
|
|
455
|
+
const suppressNextBlur = useRef2(false);
|
|
456
|
+
const [validationError, setValidationError] = useState2(null);
|
|
457
|
+
const [validationVariant, setValidationVariant] = useState2("error");
|
|
458
|
+
const fieldProjection = useMemo2(() => {
|
|
459
|
+
if (!model || !editing) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const { col } = parseCellIndex2(editing.index);
|
|
463
|
+
const field = model.projection.getFields()[col];
|
|
464
|
+
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
465
|
+
invariant2(fieldProjection2, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 59, S: void 0, A: ["fieldProjection", ""] });
|
|
466
|
+
return fieldProjection2;
|
|
467
|
+
}, [
|
|
468
|
+
model,
|
|
469
|
+
editing
|
|
470
|
+
]);
|
|
471
|
+
const handleEnter = useCallback2(async (value) => {
|
|
472
|
+
if (!model || !editing) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const cell = parseCellIndex2(editing.index);
|
|
476
|
+
const validationResult = await model.validateCellData(cell, value);
|
|
477
|
+
if (validationResult.valid) {
|
|
478
|
+
setValidationError(null);
|
|
479
|
+
model.setCellData(cell, value);
|
|
480
|
+
onFocus?.();
|
|
481
|
+
setEditing(null);
|
|
482
|
+
onSave?.();
|
|
483
|
+
} else {
|
|
484
|
+
setValidationError(validationResult.error);
|
|
485
|
+
setValidationVariant("error");
|
|
486
|
+
}
|
|
487
|
+
}, [
|
|
488
|
+
model,
|
|
489
|
+
editing,
|
|
490
|
+
onFocus,
|
|
491
|
+
setEditing
|
|
492
|
+
]);
|
|
493
|
+
const handleBlur = useCallback2(async (value) => {
|
|
494
|
+
if (suppressNextBlur.current) {
|
|
495
|
+
suppressNextBlur.current = false;
|
|
496
|
+
} else if (model && editing) {
|
|
497
|
+
const cell = parseCellIndex2(editing.index);
|
|
498
|
+
if (value !== void 0) {
|
|
499
|
+
const result = await model.validateCellData(cell, value);
|
|
500
|
+
if (result.valid) {
|
|
501
|
+
setValidationError(null);
|
|
502
|
+
model.setCellData(cell, value);
|
|
503
|
+
setEditing(null);
|
|
504
|
+
onSave?.();
|
|
505
|
+
}
|
|
910
506
|
}
|
|
911
|
-
});
|
|
912
|
-
this._rows = signal3([]);
|
|
913
|
-
//
|
|
914
|
-
// Data
|
|
915
|
-
//
|
|
916
|
-
this.setRows = (obj) => {
|
|
917
|
-
this._rows.value = obj;
|
|
918
|
-
};
|
|
919
|
-
this.getRowCount = () => this._rows.value.length;
|
|
920
|
-
this.getColumnCount = () => this._view?.fields.length ?? 0;
|
|
921
|
-
this.insertRow = (rowIndex) => {
|
|
922
|
-
const row = rowIndex !== void 0 ? this._sorting.getDataIndex(rowIndex) : this._rows.value.length;
|
|
923
|
-
this._onInsertRow?.(row);
|
|
924
|
-
};
|
|
925
|
-
this.deleteRow = (rowIndex) => {
|
|
926
|
-
const row = this._sorting.getDataIndex(rowIndex);
|
|
927
|
-
const obj = this._rows.value[row];
|
|
928
|
-
const objectsToDelete = [];
|
|
929
|
-
if (this.features.selection.enabled && this._selection.hasSelection.value) {
|
|
930
|
-
const selectedRows = this._selection.getSelectedRows();
|
|
931
|
-
objectsToDelete.push(...selectedRows);
|
|
932
|
-
} else {
|
|
933
|
-
objectsToDelete.push(obj);
|
|
934
|
-
}
|
|
935
|
-
this._onDeleteRows?.(row, objectsToDelete);
|
|
936
|
-
};
|
|
937
|
-
this.handleRowAction = (actionId, rowIndex) => {
|
|
938
|
-
if (!this._onRowAction) {
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
const row = this._sorting.getDataIndex(rowIndex);
|
|
942
|
-
const data = this._rows.value[row];
|
|
943
|
-
if (data) {
|
|
944
|
-
this._onRowAction(actionId, data);
|
|
945
|
-
}
|
|
946
|
-
};
|
|
947
|
-
this.getCellData = ({ col, row }) => {
|
|
948
|
-
const fields = this._view?.fields ?? [];
|
|
949
|
-
if (col < 0 || col >= fields.length) {
|
|
950
|
-
return void 0;
|
|
951
|
-
}
|
|
952
|
-
const field = fields[col];
|
|
953
|
-
const dataIndex = this._sorting.getDataIndex(row);
|
|
954
|
-
const value = getValue2(this._rows.value[dataIndex], field.path);
|
|
955
|
-
if (value == null) {
|
|
956
|
-
return "";
|
|
957
|
-
}
|
|
958
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
959
|
-
switch (props.format) {
|
|
960
|
-
case FormatEnum3.Ref: {
|
|
961
|
-
if (!field.referencePath) {
|
|
962
|
-
return "";
|
|
963
|
-
}
|
|
964
|
-
return getValue2(value.target, field.referencePath);
|
|
965
|
-
}
|
|
966
|
-
default: {
|
|
967
|
-
return formatForEditing({
|
|
968
|
-
type: props.type,
|
|
969
|
-
format: props.format,
|
|
970
|
-
value
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
};
|
|
975
|
-
this.validateCellData = async ({ col, row }, value) => {
|
|
976
|
-
const rowIdx = this._sorting.getDataIndex(row);
|
|
977
|
-
const fields = this._view?.fields ?? [];
|
|
978
|
-
if (col < 0 || col >= fields.length) {
|
|
979
|
-
return {
|
|
980
|
-
valid: false,
|
|
981
|
-
error: "Invalid column index"
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
|
-
const field = fields[col];
|
|
985
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
986
|
-
const currentRow = this._rows.value[rowIdx];
|
|
987
|
-
invariant(currentRow, "Invalid row index", {
|
|
988
|
-
F: __dxlog_file,
|
|
989
|
-
L: 355,
|
|
990
|
-
S: this,
|
|
991
|
-
A: [
|
|
992
|
-
"currentRow",
|
|
993
|
-
"'Invalid row index'"
|
|
994
|
-
]
|
|
995
|
-
});
|
|
996
|
-
const snapshot = getSnapshot(currentRow);
|
|
997
|
-
const transformedValue = editorTextToCellValue(props, value);
|
|
998
|
-
setValue(snapshot, field.path, transformedValue);
|
|
999
|
-
const schema = getSchema(currentRow);
|
|
1000
|
-
invariant(schema, void 0, {
|
|
1001
|
-
F: __dxlog_file,
|
|
1002
|
-
L: 365,
|
|
1003
|
-
S: this,
|
|
1004
|
-
A: [
|
|
1005
|
-
"schema",
|
|
1006
|
-
""
|
|
1007
|
-
]
|
|
1008
|
-
});
|
|
1009
|
-
const validationResult = validateSchema(schema, snapshot);
|
|
1010
|
-
if (validationResult && validationResult.length > 0) {
|
|
1011
|
-
const error = validationResult[0];
|
|
1012
|
-
invariant(error.path === field.path, void 0, {
|
|
1013
|
-
F: __dxlog_file,
|
|
1014
|
-
L: 370,
|
|
1015
|
-
S: this,
|
|
1016
|
-
A: [
|
|
1017
|
-
"error.path === field.path",
|
|
1018
|
-
""
|
|
1019
|
-
]
|
|
1020
|
-
});
|
|
1021
|
-
return {
|
|
1022
|
-
valid: false,
|
|
1023
|
-
error: error.message
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
return {
|
|
1027
|
-
valid: true
|
|
1028
|
-
};
|
|
1029
|
-
};
|
|
1030
|
-
this.setCellData = ({ col, row }, value) => {
|
|
1031
|
-
const rowIdx = this._sorting.getDataIndex(row);
|
|
1032
|
-
const fields = this._view?.fields ?? [];
|
|
1033
|
-
if (col < 0 || col >= fields.length) {
|
|
1034
|
-
return;
|
|
1035
|
-
}
|
|
1036
|
-
const field = fields[col];
|
|
1037
|
-
const { props } = this._projection.getFieldProjection(field.id);
|
|
1038
|
-
const transformedValue = editorTextToCellValue(props, value);
|
|
1039
|
-
if (props.format === FormatEnum3.Ref && !isLiveObject(value)) {
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
setValue(this._rows.value[rowIdx], field.path, transformedValue);
|
|
1043
|
-
};
|
|
1044
|
-
this._id = id;
|
|
1045
|
-
this._space = space;
|
|
1046
|
-
this._view = view;
|
|
1047
|
-
this._projection = projection;
|
|
1048
|
-
this._features = {
|
|
1049
|
-
...defaultFeatures,
|
|
1050
|
-
...features
|
|
1051
|
-
};
|
|
1052
|
-
invariant(!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === "single"), "Single selection is not compatible with editable tables.", {
|
|
1053
|
-
F: __dxlog_file,
|
|
1054
|
-
L: 126,
|
|
1055
|
-
S: this,
|
|
1056
|
-
A: [
|
|
1057
|
-
"!(this._features.dataEditable && this._features.selection.enabled && this._features.selection.mode === 'single')",
|
|
1058
|
-
"'Single selection is not compatible with editable tables.'"
|
|
1059
|
-
]
|
|
1060
|
-
});
|
|
1061
|
-
this._sorting = new TableSorting(this._rows, this._view, projection);
|
|
1062
|
-
if (sorting.length > 0) {
|
|
1063
|
-
const [sort] = sorting;
|
|
1064
|
-
this._sorting.setSort(sort.fieldId, sort.direction);
|
|
1065
507
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
this._onRowOrderChange = onRowOrderChange;
|
|
1073
|
-
this._onRowAction = onRowAction;
|
|
1074
|
-
}
|
|
1075
|
-
get id() {
|
|
1076
|
-
return this._id;
|
|
1077
|
-
}
|
|
1078
|
-
get space() {
|
|
1079
|
-
return this._space;
|
|
1080
|
-
}
|
|
1081
|
-
get view() {
|
|
1082
|
-
return this._view;
|
|
1083
|
-
}
|
|
1084
|
-
get projection() {
|
|
1085
|
-
return this._projection;
|
|
1086
|
-
}
|
|
1087
|
-
get rows() {
|
|
1088
|
-
return this._sorting.sortedRows;
|
|
1089
|
-
}
|
|
1090
|
-
get features() {
|
|
1091
|
-
return this._features;
|
|
1092
|
-
}
|
|
1093
|
-
/**
|
|
1094
|
-
* @reactive
|
|
1095
|
-
*/
|
|
1096
|
-
get sorting() {
|
|
1097
|
-
return this._sorting;
|
|
1098
|
-
}
|
|
1099
|
-
/**
|
|
1100
|
-
* Gets the row data at the specified display index.
|
|
1101
|
-
*/
|
|
1102
|
-
getRowAt(displayIndex) {
|
|
1103
|
-
if (displayIndex < 0 || displayIndex >= this._sorting.sortedRows.value.length) {
|
|
1104
|
-
return void 0;
|
|
1105
|
-
}
|
|
1106
|
-
return this._sorting.sortedRows.value[displayIndex];
|
|
1107
|
-
}
|
|
1108
|
-
get pinnedRows() {
|
|
1109
|
-
return this._pinnedRows;
|
|
1110
|
-
}
|
|
1111
|
-
get columnMeta() {
|
|
1112
|
-
invariant(this._columnMeta, void 0, {
|
|
1113
|
-
F: __dxlog_file,
|
|
1114
|
-
L: 195,
|
|
1115
|
-
S: this,
|
|
1116
|
-
A: [
|
|
1117
|
-
"this._columnMeta",
|
|
1118
|
-
""
|
|
1119
|
-
]
|
|
1120
|
-
});
|
|
1121
|
-
return this._columnMeta;
|
|
1122
|
-
}
|
|
1123
|
-
get selection() {
|
|
1124
|
-
return this._selection;
|
|
1125
|
-
}
|
|
1126
|
-
/** @reactive */
|
|
1127
|
-
get isViewDirty() {
|
|
1128
|
-
return this._sorting.isDirty;
|
|
1129
|
-
}
|
|
1130
|
-
get rowActions() {
|
|
1131
|
-
return this._rowActions;
|
|
1132
|
-
}
|
|
1133
|
-
//
|
|
1134
|
-
// Initialisation
|
|
1135
|
-
//
|
|
1136
|
-
async _open() {
|
|
1137
|
-
this.initializeColumnMeta();
|
|
1138
|
-
this.initializeEffects();
|
|
1139
|
-
this._selection = new SelectionModel(this._sorting.sortedRows, this._features.selection.mode ?? "multiple", () => this._onRowOrderChange?.());
|
|
1140
|
-
await this._selection.open(this._ctx);
|
|
1141
|
-
}
|
|
1142
|
-
initializeColumnMeta() {
|
|
1143
|
-
this._columnMeta = computed3(() => {
|
|
1144
|
-
const fields = this._view?.fields ?? [];
|
|
1145
|
-
const meta = Object.fromEntries(fields.map((field, index) => [
|
|
1146
|
-
index,
|
|
1147
|
-
{
|
|
1148
|
-
size: field?.size ?? 256,
|
|
1149
|
-
resizeable: true
|
|
1150
|
-
}
|
|
1151
|
-
]));
|
|
1152
|
-
return {
|
|
1153
|
-
grid: meta,
|
|
1154
|
-
frozenColsStart: {
|
|
1155
|
-
0: {
|
|
1156
|
-
size: 30,
|
|
1157
|
-
resizeable: false
|
|
1158
|
-
}
|
|
1159
|
-
},
|
|
1160
|
-
frozenColsEnd: {
|
|
1161
|
-
0: {
|
|
1162
|
-
size: 40,
|
|
1163
|
-
resizeable: false
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
};
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
initializeEffects() {
|
|
1170
|
-
const rowOrderWatcher = effect2(() => {
|
|
1171
|
-
touch(this._sorting.sortedRows.value);
|
|
1172
|
-
this._onRowOrderChange?.();
|
|
1173
|
-
});
|
|
1174
|
-
this._ctx.onDispose(rowOrderWatcher);
|
|
1175
|
-
const rowEffectManager = effect2(() => {
|
|
1176
|
-
const { start, end } = touch(this._visibleRange.value);
|
|
1177
|
-
const rowEffects = [];
|
|
1178
|
-
for (let row = start.row; row <= end.row; row++) {
|
|
1179
|
-
rowEffects.push(effect2(() => {
|
|
1180
|
-
const obj = this._sorting.sortedRows.value[row];
|
|
1181
|
-
this._view?.fields.forEach((field) => touch(getValue2(obj, field.path)));
|
|
1182
|
-
this._onCellUpdate?.({
|
|
1183
|
-
row,
|
|
1184
|
-
col: start.col,
|
|
1185
|
-
plane: "grid"
|
|
1186
|
-
});
|
|
1187
|
-
}));
|
|
1188
|
-
}
|
|
1189
|
-
return () => rowEffects.forEach((cleanup) => cleanup());
|
|
1190
|
-
});
|
|
1191
|
-
this._ctx.onDispose(rowEffectManager);
|
|
1192
|
-
}
|
|
1193
|
-
/**
|
|
1194
|
-
* Updates a cell's value using a transform function.
|
|
1195
|
-
* @param {DxGridPlanePosition} position - The position of the cell to update.
|
|
1196
|
-
* @param {(value: any) => any} update - A function that takes the current value and returns the updated value.
|
|
1197
|
-
*/
|
|
1198
|
-
updateCellData({ col, row }, update) {
|
|
1199
|
-
const dataRow = this._sorting.getDataIndex(row);
|
|
1200
|
-
const fields = this._view?.fields ?? [];
|
|
1201
|
-
const field = fields[col];
|
|
1202
|
-
const value = getValue2(this._rows.value[dataRow], field.path);
|
|
1203
|
-
const updatedValue = update(value);
|
|
1204
|
-
setValue(this._rows.value[dataRow], field.path, updatedValue);
|
|
1205
|
-
}
|
|
1206
|
-
//
|
|
1207
|
-
// Column Operations
|
|
1208
|
-
//
|
|
1209
|
-
deleteColumn(fieldId) {
|
|
1210
|
-
if (!this._view) {
|
|
508
|
+
}, [
|
|
509
|
+
model,
|
|
510
|
+
editing
|
|
511
|
+
]);
|
|
512
|
+
const handleClose = useCallback2(async (value, event) => {
|
|
513
|
+
if (!model || !editing || !fieldProjection) {
|
|
1211
514
|
return;
|
|
1212
515
|
}
|
|
1213
|
-
const
|
|
1214
|
-
if (
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
//
|
|
1219
|
-
// Resize
|
|
1220
|
-
//
|
|
1221
|
-
setColumnWidth(columnIndex, width) {
|
|
1222
|
-
const fields = this._view?.fields ?? [];
|
|
1223
|
-
if (columnIndex < fields.length) {
|
|
1224
|
-
const newWidth = Math.max(0, width);
|
|
1225
|
-
const field = fields[columnIndex];
|
|
1226
|
-
if (field) {
|
|
1227
|
-
field.size = newWidth;
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
//
|
|
1232
|
-
// Pinning
|
|
1233
|
-
//
|
|
1234
|
-
// TODO(burdon): Change to setPinned(on/off).
|
|
1235
|
-
pinRow(rowIndex, side) {
|
|
1236
|
-
this._pinnedRows[side].push(rowIndex);
|
|
1237
|
-
}
|
|
1238
|
-
unpinRow(rowIndex) {
|
|
1239
|
-
this._pinnedRows.top = this._pinnedRows.top.filter((index) => index !== rowIndex);
|
|
1240
|
-
this._pinnedRows.bottom = this._pinnedRows.bottom.filter((index) => index !== rowIndex);
|
|
1241
|
-
}
|
|
1242
|
-
//
|
|
1243
|
-
// View operations
|
|
1244
|
-
//
|
|
1245
|
-
saveView() {
|
|
1246
|
-
this._sorting.save();
|
|
1247
|
-
}
|
|
1248
|
-
};
|
|
1249
|
-
var editorTextToCellValue = (props, value) => {
|
|
1250
|
-
switch (props.format) {
|
|
1251
|
-
case FormatEnum3.Ref: {
|
|
1252
|
-
if (isLiveObject(value)) {
|
|
1253
|
-
return makeRef(value);
|
|
1254
|
-
} else {
|
|
1255
|
-
return value;
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
case FormatEnum3.SingleSelect: {
|
|
1259
|
-
const ids = extractTagIds(value);
|
|
1260
|
-
if (ids && ids.length > 0) {
|
|
1261
|
-
return ids[0];
|
|
1262
|
-
} else {
|
|
1263
|
-
return value;
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
case FormatEnum3.MultiSelect: {
|
|
1267
|
-
const ids = extractTagIds(value);
|
|
1268
|
-
return ids || value;
|
|
1269
|
-
}
|
|
1270
|
-
default: {
|
|
1271
|
-
return parseValue({
|
|
1272
|
-
type: props.type,
|
|
1273
|
-
format: props.format,
|
|
1274
|
-
value
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1279
|
-
|
|
1280
|
-
// packages/ui/react-ui-table/src/model/modal-controller.ts
|
|
1281
|
-
import { signal as signal4 } from "@preact/signals-core";
|
|
1282
|
-
import { log } from "@dxos/log";
|
|
1283
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/model/modal-controller.ts";
|
|
1284
|
-
var ModalController = class {
|
|
1285
|
-
constructor() {
|
|
1286
|
-
this._state = signal4({
|
|
1287
|
-
type: "closed"
|
|
1288
|
-
});
|
|
1289
|
-
this._triggerRef = {
|
|
1290
|
-
current: null
|
|
1291
|
-
};
|
|
1292
|
-
this.setTrigger = (trigger) => {
|
|
1293
|
-
this._triggerRef.current = trigger;
|
|
1294
|
-
};
|
|
1295
|
-
this.showRowMenu = (rowIndex) => {
|
|
1296
|
-
this._state.value = {
|
|
1297
|
-
type: "row",
|
|
1298
|
-
rowIndex
|
|
1299
|
-
};
|
|
1300
|
-
};
|
|
1301
|
-
this.showColumnMenu = (fieldId) => {
|
|
1302
|
-
this._state.value = {
|
|
1303
|
-
type: "column",
|
|
1304
|
-
fieldId
|
|
1305
|
-
};
|
|
1306
|
-
};
|
|
1307
|
-
this.showColumnCreator = () => {
|
|
1308
|
-
this._state.value = {
|
|
1309
|
-
type: "columnSettings",
|
|
1310
|
-
mode: {
|
|
1311
|
-
type: "create"
|
|
1312
|
-
}
|
|
1313
|
-
};
|
|
1314
|
-
};
|
|
1315
|
-
this.showReferencePanel = (targetId, schemaId) => {
|
|
1316
|
-
this._state.value = {
|
|
1317
|
-
type: "refPanel",
|
|
1318
|
-
targetId,
|
|
1319
|
-
typename: schemaId
|
|
1320
|
-
};
|
|
1321
|
-
};
|
|
1322
|
-
this.openColumnSettings = () => {
|
|
1323
|
-
if (this._state.value.type === "column") {
|
|
1324
|
-
const fieldId = this._state.value.fieldId;
|
|
1325
|
-
requestAnimationFrame(() => {
|
|
1326
|
-
this._state.value = {
|
|
1327
|
-
type: "columnSettings",
|
|
1328
|
-
mode: {
|
|
1329
|
-
type: "edit",
|
|
1330
|
-
fieldId
|
|
1331
|
-
}
|
|
1332
|
-
};
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
};
|
|
1336
|
-
this.openCreateRef = (typename, anchorCell, initialValues, onCreate) => {
|
|
1337
|
-
if (anchorCell) {
|
|
1338
|
-
this._triggerRef.current = anchorCell;
|
|
1339
|
-
this._state.value = {
|
|
1340
|
-
type: "createRefPanel",
|
|
1341
|
-
typename,
|
|
1342
|
-
initialValues,
|
|
1343
|
-
onCreate
|
|
1344
|
-
};
|
|
1345
|
-
} else {
|
|
1346
|
-
log.warn("anchor cell not found while creating new ref", void 0, {
|
|
1347
|
-
F: __dxlog_file2,
|
|
1348
|
-
L: 86,
|
|
1349
|
-
S: this,
|
|
1350
|
-
C: (f, a) => f(...a)
|
|
1351
|
-
});
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1354
|
-
this.close = () => {
|
|
1355
|
-
this._state.value = {
|
|
1356
|
-
type: "closed"
|
|
1357
|
-
};
|
|
1358
|
-
};
|
|
1359
|
-
}
|
|
1360
|
-
get state() {
|
|
1361
|
-
return this._state;
|
|
1362
|
-
}
|
|
1363
|
-
get trigger() {
|
|
1364
|
-
return this._triggerRef;
|
|
1365
|
-
}
|
|
1366
|
-
};
|
|
1367
|
-
|
|
1368
|
-
// packages/ui/react-ui-table/src/model/table-presentation.ts
|
|
1369
|
-
import { signal as signal5 } from "@preact/signals-core";
|
|
1370
|
-
import { isNotNullable } from "effect/Predicate";
|
|
1371
|
-
import { FormatEnum as FormatEnum4, getObjectDXN, getValue as getValue3, TypeEnum as TypeEnum3 } from "@dxos/echo-schema";
|
|
1372
|
-
import { cellClassesForFieldType, formatForDisplay as formatForDisplay2 } from "@dxos/react-ui-form";
|
|
1373
|
-
import { toPlaneCellIndex } from "@dxos/react-ui-grid";
|
|
1374
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
1375
|
-
import { VIEW_FIELD_LIMIT } from "@dxos/schema";
|
|
1376
|
-
var TablePresentation = class {
|
|
1377
|
-
constructor(model, _visibleRange = signal5({
|
|
1378
|
-
start: {
|
|
1379
|
-
row: 0,
|
|
1380
|
-
col: 0
|
|
1381
|
-
},
|
|
1382
|
-
end: {
|
|
1383
|
-
row: 0,
|
|
1384
|
-
col: 0
|
|
1385
|
-
}
|
|
1386
|
-
})) {
|
|
1387
|
-
this.model = model;
|
|
1388
|
-
this._visibleRange = _visibleRange;
|
|
1389
|
-
}
|
|
1390
|
-
getCells(range, plane) {
|
|
1391
|
-
let cells;
|
|
1392
|
-
switch (plane) {
|
|
1393
|
-
case "grid":
|
|
1394
|
-
this._visibleRange.value = range;
|
|
1395
|
-
cells = this.getMainGridCells(range);
|
|
1396
|
-
break;
|
|
1397
|
-
case "frozenRowsStart":
|
|
1398
|
-
cells = this.getHeaderCells(range);
|
|
1399
|
-
break;
|
|
1400
|
-
case "frozenColsStart":
|
|
1401
|
-
cells = this.getSelectionColumnCells(range);
|
|
1402
|
-
break;
|
|
1403
|
-
case "frozenColsEnd":
|
|
1404
|
-
cells = this.getActionColumnCells(range);
|
|
1405
|
-
break;
|
|
1406
|
-
case "fixedStartStart":
|
|
1407
|
-
cells = this.getSelectAllCell();
|
|
1408
|
-
break;
|
|
1409
|
-
case "fixedStartEnd":
|
|
1410
|
-
cells = this.getNewColumnCell();
|
|
1411
|
-
break;
|
|
1412
|
-
default:
|
|
1413
|
-
cells = {};
|
|
1414
|
-
}
|
|
1415
|
-
if (plane === "grid" && this.model.features.dataEditable === false) {
|
|
1416
|
-
Object.values(cells).forEach((cell) => {
|
|
1417
|
-
cell.readonly = "text-select";
|
|
1418
|
-
});
|
|
1419
|
-
}
|
|
1420
|
-
return cells;
|
|
1421
|
-
}
|
|
1422
|
-
getMainGridCells(range) {
|
|
1423
|
-
const cells = {};
|
|
1424
|
-
const fields = this.model.view?.fields ?? [];
|
|
1425
|
-
const addCell = (obj, field, colIndex, displayIndex) => {
|
|
1426
|
-
const { props } = this.model.projection.getFieldProjection(field.id);
|
|
1427
|
-
const cell = {
|
|
1428
|
-
get value() {
|
|
1429
|
-
const value = getValue3(obj, field.path);
|
|
1430
|
-
if (value == null) {
|
|
1431
|
-
return "";
|
|
1432
|
-
}
|
|
1433
|
-
if (props.type === "array") {
|
|
1434
|
-
return "";
|
|
1435
|
-
}
|
|
1436
|
-
switch (props.format) {
|
|
1437
|
-
case FormatEnum4.Boolean:
|
|
1438
|
-
case FormatEnum4.SingleSelect:
|
|
1439
|
-
case FormatEnum4.MultiSelect: {
|
|
1440
|
-
return "";
|
|
1441
|
-
}
|
|
1442
|
-
case FormatEnum4.Ref: {
|
|
1443
|
-
if (!field.referencePath) {
|
|
1444
|
-
return "";
|
|
1445
|
-
}
|
|
1446
|
-
return getValue3(value.target, field.referencePath);
|
|
1447
|
-
}
|
|
1448
|
-
default: {
|
|
1449
|
-
return formatForDisplay2({
|
|
1450
|
-
type: props.type,
|
|
1451
|
-
format: props.format,
|
|
1452
|
-
value
|
|
1453
|
-
});
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
};
|
|
1458
|
-
const classes = [];
|
|
1459
|
-
const formatClasses = cellClassesForFieldType({
|
|
1460
|
-
type: props.type,
|
|
1461
|
-
format: props.format
|
|
1462
|
-
});
|
|
1463
|
-
if (formatClasses) {
|
|
1464
|
-
classes.push(formatClasses);
|
|
1465
|
-
}
|
|
1466
|
-
const rowSelectionClasses = cellClassesForRowSelection(this.model.selection.isObjectSelected(obj), this.model.selection.selectionMode);
|
|
1467
|
-
if (rowSelectionClasses) {
|
|
1468
|
-
classes.push(rowSelectionClasses);
|
|
1469
|
-
}
|
|
1470
|
-
if (classes.length > 0) {
|
|
1471
|
-
cell.className = mx(classes.flat());
|
|
1472
|
-
}
|
|
1473
|
-
if (props.type === TypeEnum3.Array) {
|
|
1474
|
-
const targetArray = getValue3(obj, field.path);
|
|
1475
|
-
if (targetArray && Array.isArray(targetArray)) {
|
|
1476
|
-
const getLabel = (value) => {
|
|
1477
|
-
if (!value) {
|
|
1478
|
-
return void 0;
|
|
1479
|
-
}
|
|
1480
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1481
|
-
return String(value);
|
|
1482
|
-
}
|
|
1483
|
-
if (Array.isArray(value)) {
|
|
1484
|
-
return "Array";
|
|
1485
|
-
}
|
|
1486
|
-
if (typeof value === "object" && value.name) {
|
|
1487
|
-
return value.name;
|
|
1488
|
-
}
|
|
1489
|
-
if (typeof value === "object" && value.value) {
|
|
1490
|
-
return `${value.value}`;
|
|
1491
|
-
}
|
|
1492
|
-
return "Object";
|
|
1493
|
-
};
|
|
1494
|
-
const tags = targetArray.map(getLabel).filter(isNotNullable).map((title) => {
|
|
1495
|
-
return `<span class="dx-tag rounded-xl" data-hue="neutral">${title}</span>`;
|
|
1496
|
-
}).join("");
|
|
1497
|
-
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1 overflow-x-auto">${tags}</div>`;
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
if (props.format === FormatEnum4.Ref && props.referenceSchema) {
|
|
1501
|
-
const targetObj = getValue3(obj, field.path)?.target;
|
|
1502
|
-
if (targetObj) {
|
|
1503
|
-
const dxn = getObjectDXN(targetObj)?.toString();
|
|
1504
|
-
cell.accessoryHtml = `<dx-ref-tag refId=${dxn} class="dx-button is-6 pli-[3px] pbe-[2px] min-bs-0 absolute inline-end-1"><dx-icon icon="ph--link-simple--regular"/></dx-ref-tag>`;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
if (props.format === FormatEnum4.Boolean) {
|
|
1508
|
-
const value = getValue3(obj, field.path);
|
|
1509
|
-
cell.accessoryHtml = tableControls.switch.render({
|
|
1510
|
-
colIndex,
|
|
1511
|
-
rowIndex: displayIndex,
|
|
1512
|
-
checked: value ?? false
|
|
1513
|
-
});
|
|
1514
|
-
cell.readonly = "no-text-select";
|
|
1515
|
-
}
|
|
1516
|
-
if (props.format === FormatEnum4.SingleSelect) {
|
|
1517
|
-
const value = getValue3(obj, field.path);
|
|
1518
|
-
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1519
|
-
if (options) {
|
|
1520
|
-
const option = options.find((o) => o.id === value);
|
|
1521
|
-
if (option) {
|
|
1522
|
-
cell.accessoryHtml = `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
if (props.format === FormatEnum4.MultiSelect) {
|
|
1527
|
-
const values = getValue3(obj, field.path);
|
|
1528
|
-
const options = this.model.projection.getFieldProjection(field.id).props.options;
|
|
1529
|
-
if (options && values && values.length > 0) {
|
|
1530
|
-
const tags = values.map((value) => {
|
|
1531
|
-
const option = options.find((o) => o.id === value);
|
|
1532
|
-
if (option) {
|
|
1533
|
-
return `<span class="dx-tag" data-hue="${option.color}">${option.title}</span>`;
|
|
1534
|
-
}
|
|
1535
|
-
return null;
|
|
1536
|
-
}).filter(Boolean).join(" ");
|
|
1537
|
-
if (tags) {
|
|
1538
|
-
cell.accessoryHtml = `<div role='none' class="flex flex-row gap-1">${tags}</div>`;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
const idx = toPlaneCellIndex({
|
|
1543
|
-
col: colIndex,
|
|
1544
|
-
row: displayIndex
|
|
1545
|
-
});
|
|
1546
|
-
cells[idx] = cell;
|
|
1547
|
-
};
|
|
1548
|
-
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1549
|
-
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1550
|
-
const field = fields[col];
|
|
1551
|
-
if (!field) {
|
|
1552
|
-
continue;
|
|
1553
|
-
}
|
|
1554
|
-
addCell(this.model.rows.value[row], field, col, row);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
return cells;
|
|
1558
|
-
}
|
|
1559
|
-
getHeaderCells(range) {
|
|
1560
|
-
const cells = {};
|
|
1561
|
-
const fields = this.model.view?.fields ?? [];
|
|
1562
|
-
for (let col = range.start.col; col <= range.end.col && col < fields.length; col++) {
|
|
1563
|
-
const { field, props } = this.model.projection.getFieldProjection(fields[col].id);
|
|
1564
|
-
const sorting = this.model.sorting?.sorting;
|
|
1565
|
-
const direction = sorting?.fieldId === field.id ? sorting.direction : void 0;
|
|
1566
|
-
cells[toPlaneCellIndex({
|
|
1567
|
-
col,
|
|
1568
|
-
row: 0
|
|
1569
|
-
})] = {
|
|
1570
|
-
// TODO(burdon): Use same logic as form for fallback title.
|
|
1571
|
-
value: props.title ?? field.path,
|
|
1572
|
-
readonly: true,
|
|
1573
|
-
resizeHandle: "col",
|
|
1574
|
-
accessoryHtml: `
|
|
1575
|
-
${direction !== void 0 ? tableButtons.sort.render({
|
|
1576
|
-
fieldId: field.id,
|
|
1577
|
-
direction
|
|
1578
|
-
}) : ""}
|
|
1579
|
-
${tableButtons.columnSettings.render({
|
|
1580
|
-
fieldId: field.id
|
|
1581
|
-
})}
|
|
1582
|
-
`,
|
|
1583
|
-
className: "!bg-toolbarSurface"
|
|
1584
|
-
};
|
|
1585
|
-
}
|
|
1586
|
-
return cells;
|
|
1587
|
-
}
|
|
1588
|
-
getSelectionColumnCells(range) {
|
|
1589
|
-
const cells = {};
|
|
1590
|
-
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1591
|
-
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
1592
|
-
const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
|
|
1593
|
-
cells[toPlaneCellIndex({
|
|
1594
|
-
col: 0,
|
|
1595
|
-
row
|
|
1596
|
-
})] = {
|
|
1597
|
-
value: "",
|
|
1598
|
-
readonly: "no-text-select",
|
|
1599
|
-
className: classes ? mx(classes) : void 0,
|
|
1600
|
-
accessoryHtml: tableControls.checkbox.render({
|
|
1601
|
-
rowIndex: row,
|
|
1602
|
-
checked: isSelected
|
|
1603
|
-
})
|
|
1604
|
-
};
|
|
1605
|
-
}
|
|
1606
|
-
return cells;
|
|
1607
|
-
}
|
|
1608
|
-
getActionColumnCells(range) {
|
|
1609
|
-
const cells = {};
|
|
1610
|
-
for (let row = range.start.row; row <= range.end.row && row < this.model.getRowCount(); row++) {
|
|
1611
|
-
const isSelected = this.model.selection.isRowIndexSelected(row);
|
|
1612
|
-
const classes = cellClassesForRowSelection(isSelected, this.model.selection.selectionMode);
|
|
1613
|
-
cells[toPlaneCellIndex({
|
|
1614
|
-
col: 0,
|
|
1615
|
-
row
|
|
1616
|
-
})] = {
|
|
1617
|
-
value: "",
|
|
1618
|
-
readonly: true,
|
|
1619
|
-
className: classes ? mx(classes) : void 0,
|
|
1620
|
-
accessoryHtml: tableButtons.rowMenu.render({
|
|
1621
|
-
rowIndex: row
|
|
1622
|
-
})
|
|
1623
|
-
};
|
|
1624
|
-
}
|
|
1625
|
-
return cells;
|
|
1626
|
-
}
|
|
1627
|
-
getSelectAllCell() {
|
|
1628
|
-
if (!this.model.features.selection.enabled || this.model.selection.selectionMode === "single") {
|
|
1629
|
-
return {
|
|
1630
|
-
[toPlaneCellIndex({
|
|
1631
|
-
col: 0,
|
|
1632
|
-
row: 0
|
|
1633
|
-
})]: {
|
|
1634
|
-
className: "!bg-toolbarSurface",
|
|
1635
|
-
readonly: true,
|
|
1636
|
-
value: ""
|
|
1637
|
-
}
|
|
1638
|
-
};
|
|
1639
|
-
}
|
|
1640
|
-
return {
|
|
1641
|
-
[toPlaneCellIndex({
|
|
1642
|
-
col: 0,
|
|
1643
|
-
row: 0
|
|
1644
|
-
})]: {
|
|
1645
|
-
accessoryHtml: tableControls.checkbox.render({
|
|
1646
|
-
rowIndex: 0,
|
|
1647
|
-
header: true,
|
|
1648
|
-
checked: this.model.selection.allRowsSeleted.value
|
|
1649
|
-
}),
|
|
1650
|
-
className: "!bg-toolbarSurface",
|
|
1651
|
-
readonly: true,
|
|
1652
|
-
value: ""
|
|
1653
|
-
}
|
|
1654
|
-
};
|
|
1655
|
-
}
|
|
1656
|
-
getNewColumnCell() {
|
|
1657
|
-
return {
|
|
1658
|
-
[toPlaneCellIndex({
|
|
1659
|
-
col: 0,
|
|
1660
|
-
row: 0
|
|
1661
|
-
})]: {
|
|
1662
|
-
accessoryHtml: this.model.features.schemaEditable ? tableButtons.addColumn.render({
|
|
1663
|
-
disabled: (this.model.view?.fields?.length ?? 0) >= VIEW_FIELD_LIMIT
|
|
1664
|
-
}) : void 0,
|
|
1665
|
-
className: "!bg-toolbarSurface",
|
|
1666
|
-
readonly: true,
|
|
1667
|
-
value: ""
|
|
1668
|
-
}
|
|
1669
|
-
};
|
|
1670
|
-
}
|
|
1671
|
-
};
|
|
1672
|
-
var cellClassesForRowSelection = (selected, selectionMode) => {
|
|
1673
|
-
if (!selected) {
|
|
1674
|
-
if (selectionMode === "single") {
|
|
1675
|
-
return [
|
|
1676
|
-
"!cursor-pointer"
|
|
1677
|
-
];
|
|
1678
|
-
} else {
|
|
1679
|
-
return void 0;
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
switch (selectionMode) {
|
|
1683
|
-
case "single":
|
|
1684
|
-
return [
|
|
1685
|
-
"!bg-currentRelated hover:bg-hoverSurface",
|
|
1686
|
-
"!cursor-pointer"
|
|
1687
|
-
];
|
|
1688
|
-
case "multiple":
|
|
1689
|
-
return [
|
|
1690
|
-
"!bg-gridCellSelected"
|
|
1691
|
-
];
|
|
1692
|
-
}
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
|
-
// packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
|
|
1696
|
-
import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
|
|
1697
|
-
import React7, { useCallback as useCallback4, useMemo as useMemo4, useRef as useRef2, useState as useState2 } from "react";
|
|
1698
|
-
import { FormatEnum as FormatEnum5, TypeEnum as TypeEnum4 } from "@dxos/echo-schema";
|
|
1699
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1700
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
1701
|
-
import { createMarkdownExtensions } from "@dxos/react-ui-editor";
|
|
1702
|
-
import { cellQuery, editorKeys, parseCellIndex as parseCellIndex2, useGridContext as useGridContext4, GridCellEditor } from "@dxos/react-ui-grid";
|
|
1703
|
-
import { tagPickerExtension, createLinks } from "@dxos/react-ui-tag-picker";
|
|
1704
|
-
|
|
1705
|
-
// packages/ui/react-ui-table/src/components/TableCellEditor/CellValidationMessage.tsx
|
|
1706
|
-
import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
|
|
1707
|
-
import React5 from "react";
|
|
1708
|
-
import { useGridContext as useGridContext2 } from "@dxos/react-ui-grid";
|
|
1709
|
-
var CellValidationMessage = ({ validationError, __gridScope }) => {
|
|
1710
|
-
var _effect = _useSignals5();
|
|
1711
|
-
try {
|
|
1712
|
-
const { editing, editBox: box } = useGridContext2("GridSheetCellEditor", __gridScope);
|
|
1713
|
-
if (!editing || !validationError) {
|
|
1714
|
-
return null;
|
|
1715
|
-
}
|
|
1716
|
-
return /* @__PURE__ */ React5.createElement("div", {
|
|
1717
|
-
role: "none",
|
|
1718
|
-
className: "absolute bg-errorSurface text-errorSurfaceText rounded-bs-sm text-xs p-1",
|
|
1719
|
-
style: {
|
|
1720
|
-
...{
|
|
1721
|
-
"--dx-gridCellWidth": `${box?.inlineSize ?? 200}px`
|
|
1722
|
-
},
|
|
1723
|
-
zIndex: 10,
|
|
1724
|
-
insetBlockEnd: `calc(100% - ${box.insetBlockStart}px)`,
|
|
1725
|
-
insetInlineStart: box.insetInlineStart,
|
|
1726
|
-
inlineSize: box.inlineSize
|
|
1727
|
-
}
|
|
1728
|
-
}, validationError);
|
|
1729
|
-
} finally {
|
|
1730
|
-
_effect.f();
|
|
1731
|
-
}
|
|
1732
|
-
};
|
|
1733
|
-
|
|
1734
|
-
// packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx
|
|
1735
|
-
import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
|
|
1736
|
-
import React6, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
|
|
1737
|
-
import { getSnapshot as getSnapshot2 } from "@dxos/echo-schema";
|
|
1738
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1739
|
-
import { Popover as Popover3 } from "@dxos/react-ui";
|
|
1740
|
-
import { Form as Form2 } from "@dxos/react-ui-form";
|
|
1741
|
-
import { parseCellIndex, useGridContext as useGridContext3 } from "@dxos/react-ui-grid";
|
|
1742
|
-
import { getDeep, setDeep } from "@dxos/util";
|
|
1743
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/FormCellEditor.tsx";
|
|
1744
|
-
var FormCellEditor = ({ fieldProjection, model, schema, __gridScope }) => {
|
|
1745
|
-
var _effect = _useSignals6();
|
|
1746
|
-
try {
|
|
1747
|
-
const { editing, setEditing } = useGridContext3("ArrayEditor", __gridScope);
|
|
1748
|
-
const cellRef = useRef(null);
|
|
1749
|
-
useEffect2(() => {
|
|
1750
|
-
if (editing && editing.cellElement) {
|
|
1751
|
-
cellRef.current = editing.cellElement;
|
|
1752
|
-
}
|
|
1753
|
-
}, [
|
|
1754
|
-
editing?.cellElement
|
|
1755
|
-
]);
|
|
1756
|
-
const narrowedSchema = useMemo3(() => {
|
|
1757
|
-
if (!schema) {
|
|
1758
|
-
return void 0;
|
|
1759
|
-
}
|
|
1760
|
-
return narrowSchema(schema, [
|
|
1761
|
-
fieldProjection.field.path
|
|
1762
|
-
]);
|
|
1763
|
-
}, [
|
|
1764
|
-
JSON.stringify(schema),
|
|
1765
|
-
fieldProjection.field.path
|
|
1766
|
-
]);
|
|
1767
|
-
const originalRow = useMemo3(() => {
|
|
1768
|
-
if (model && editing) {
|
|
1769
|
-
const cell = parseCellIndex(editing.index);
|
|
1770
|
-
const row = model.getRowAt(cell.row);
|
|
1771
|
-
invariant2(row, void 0, {
|
|
1772
|
-
F: __dxlog_file3,
|
|
1773
|
-
L: 47,
|
|
1774
|
-
S: void 0,
|
|
1775
|
-
A: [
|
|
1776
|
-
"row",
|
|
1777
|
-
""
|
|
1778
|
-
]
|
|
1779
|
-
});
|
|
1780
|
-
return row;
|
|
1781
|
-
}
|
|
1782
|
-
return void 0;
|
|
1783
|
-
}, [
|
|
1784
|
-
model,
|
|
1785
|
-
editing
|
|
1786
|
-
]);
|
|
1787
|
-
const formValues = useMemo3(() => {
|
|
1788
|
-
if (originalRow) {
|
|
1789
|
-
return getSnapshot2(originalRow);
|
|
1790
|
-
}
|
|
1791
|
-
}, [
|
|
1792
|
-
originalRow
|
|
1793
|
-
]);
|
|
1794
|
-
const handleSave = useCallback3((values) => {
|
|
1795
|
-
const path = fieldProjection.field.path;
|
|
1796
|
-
const value = getDeep(values, [
|
|
1797
|
-
path
|
|
1798
|
-
]);
|
|
1799
|
-
setDeep(originalRow, [
|
|
1800
|
-
path
|
|
1801
|
-
], value);
|
|
1802
|
-
setEditing(null);
|
|
1803
|
-
}, [
|
|
1804
|
-
fieldProjection.field.path,
|
|
1805
|
-
originalRow
|
|
1806
|
-
]);
|
|
1807
|
-
const handleOpenChange = useCallback3((nextOpen) => {
|
|
1808
|
-
if (nextOpen === false) {
|
|
1809
|
-
setEditing(null);
|
|
1810
|
-
}
|
|
1811
|
-
}, [
|
|
1812
|
-
setEditing
|
|
1813
|
-
]);
|
|
1814
|
-
if (!editing) {
|
|
1815
|
-
return null;
|
|
1816
|
-
}
|
|
1817
|
-
return /* @__PURE__ */ React6.createElement(Popover3.Root, {
|
|
1818
|
-
open: editing !== null,
|
|
1819
|
-
onOpenChange: handleOpenChange
|
|
1820
|
-
}, /* @__PURE__ */ React6.createElement(Popover3.VirtualTrigger, {
|
|
1821
|
-
virtualRef: cellRef
|
|
1822
|
-
}), /* @__PURE__ */ React6.createElement(Popover3.Content, {
|
|
1823
|
-
tabIndex: -1,
|
|
1824
|
-
classNames: "popover-card-width"
|
|
1825
|
-
}, /* @__PURE__ */ React6.createElement(Popover3.Arrow, null), /* @__PURE__ */ React6.createElement(Popover3.Viewport, null, /* @__PURE__ */ React6.createElement(Form2, {
|
|
1826
|
-
values: formValues,
|
|
1827
|
-
schema: narrowedSchema,
|
|
1828
|
-
onSave: handleSave
|
|
1829
|
-
}))));
|
|
1830
|
-
} finally {
|
|
1831
|
-
_effect.f();
|
|
1832
|
-
}
|
|
1833
|
-
};
|
|
1834
|
-
|
|
1835
|
-
// packages/ui/react-ui-table/src/components/TableCellEditor/extension.ts
|
|
1836
|
-
import { autocompletion, pickedCompletion } from "@codemirror/autocomplete";
|
|
1837
|
-
import { EditorView } from "@codemirror/view";
|
|
1838
|
-
var completion = ({ debug, onQuery, onMatch }) => {
|
|
1839
|
-
return [
|
|
1840
|
-
EditorView.theme({
|
|
1841
|
-
".cm-completionDialog": {
|
|
1842
|
-
width: "var(--dx-gridCellWidth)"
|
|
1843
|
-
}
|
|
1844
|
-
}),
|
|
1845
|
-
autocompletion({
|
|
1846
|
-
icons: false,
|
|
1847
|
-
activateOnTyping: true,
|
|
1848
|
-
closeOnBlur: !debug,
|
|
1849
|
-
override: [
|
|
1850
|
-
async (context) => {
|
|
1851
|
-
const text = context.state.doc.toString();
|
|
1852
|
-
return {
|
|
1853
|
-
from: 0,
|
|
1854
|
-
options: await onQuery(text)
|
|
1855
|
-
};
|
|
1856
|
-
}
|
|
1857
|
-
],
|
|
1858
|
-
// TODO(burdon): Consts from grid (to line-up with grid).
|
|
1859
|
-
tooltipClass: () => "cm-completionDialog !mt-[8px] !-ml-[4px] [&>ul]:!max-h-[264px]",
|
|
1860
|
-
optionClass: () => "flex h-[33px] items-center"
|
|
1861
|
-
}),
|
|
1862
|
-
// Check for accepted completion metadata in the transaction.
|
|
1863
|
-
EditorView.updateListener.of((update) => {
|
|
1864
|
-
update.transactions.forEach((tr) => {
|
|
1865
|
-
const completion2 = tr.annotation(pickedCompletion);
|
|
1866
|
-
if (completion2) {
|
|
1867
|
-
onMatch(completion2.data);
|
|
1868
|
-
}
|
|
1869
|
-
});
|
|
1870
|
-
})
|
|
1871
|
-
];
|
|
1872
|
-
};
|
|
1873
|
-
|
|
1874
|
-
// packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx
|
|
1875
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-table/src/components/TableCellEditor/TableCellEditor.tsx";
|
|
1876
|
-
var newValue = Symbol.for("newValue");
|
|
1877
|
-
var createOption = (text) => ({
|
|
1878
|
-
[newValue]: true,
|
|
1879
|
-
text
|
|
1880
|
-
});
|
|
1881
|
-
var isCreateOption = (data) => typeof data === "object" && data[newValue];
|
|
1882
|
-
var TableValueEditor = ({ model, modals, schema, onEnter, onFocus, onQuery, __gridScope }) => {
|
|
1883
|
-
var _effect = _useSignals7();
|
|
1884
|
-
try {
|
|
1885
|
-
const { editing } = useGridContext4("TableValueEditor", __gridScope);
|
|
1886
|
-
const fieldProjection = useMemo4(() => {
|
|
1887
|
-
if (!model || !editing) {
|
|
1888
|
-
return;
|
|
1889
|
-
}
|
|
1890
|
-
const { col } = parseCellIndex2(editing.index);
|
|
1891
|
-
const field = model.projection.view.fields[col];
|
|
1892
|
-
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
1893
|
-
invariant3(fieldProjection2, void 0, {
|
|
1894
|
-
F: __dxlog_file4,
|
|
1895
|
-
L: 74,
|
|
1896
|
-
S: void 0,
|
|
1897
|
-
A: [
|
|
1898
|
-
"fieldProjection",
|
|
1899
|
-
""
|
|
1900
|
-
]
|
|
1901
|
-
});
|
|
1902
|
-
return fieldProjection2;
|
|
1903
|
-
}, [
|
|
1904
|
-
model,
|
|
1905
|
-
editing
|
|
1906
|
-
]);
|
|
1907
|
-
if (fieldProjection?.props.type === TypeEnum4.Array) {
|
|
1908
|
-
return /* @__PURE__ */ React7.createElement(FormCellEditor, {
|
|
1909
|
-
fieldProjection,
|
|
1910
|
-
model,
|
|
1911
|
-
schema,
|
|
1912
|
-
__gridScope
|
|
1913
|
-
});
|
|
1914
|
-
}
|
|
1915
|
-
return /* @__PURE__ */ React7.createElement(TableCellEditor, {
|
|
1916
|
-
model,
|
|
1917
|
-
modals,
|
|
1918
|
-
onEnter,
|
|
1919
|
-
onFocus,
|
|
1920
|
-
onQuery,
|
|
1921
|
-
__gridScope
|
|
1922
|
-
});
|
|
1923
|
-
} finally {
|
|
1924
|
-
_effect.f();
|
|
1925
|
-
}
|
|
1926
|
-
};
|
|
1927
|
-
var TableCellEditor = ({ model, modals, onEnter, onFocus, onQuery, __gridScope }) => {
|
|
1928
|
-
var _effect = _useSignals7();
|
|
1929
|
-
try {
|
|
1930
|
-
const { id: gridId, editing, setEditing } = useGridContext4("TableCellEditor", __gridScope);
|
|
1931
|
-
const suppressNextBlur = useRef2(false);
|
|
1932
|
-
const { themeMode } = useThemeContext();
|
|
1933
|
-
const [_validationError, setValidationError] = useState2(null);
|
|
1934
|
-
const fieldProjection = useMemo4(() => {
|
|
1935
|
-
if (!model || !editing) {
|
|
1936
|
-
return;
|
|
1937
|
-
}
|
|
1938
|
-
const { col } = parseCellIndex2(editing.index);
|
|
1939
|
-
const field = model.projection.view.fields[col];
|
|
1940
|
-
const fieldProjection2 = model.projection.getFieldProjection(field.id);
|
|
1941
|
-
invariant3(fieldProjection2, void 0, {
|
|
1942
|
-
F: __dxlog_file4,
|
|
1943
|
-
L: 116,
|
|
1944
|
-
S: void 0,
|
|
1945
|
-
A: [
|
|
1946
|
-
"fieldProjection",
|
|
1947
|
-
""
|
|
1948
|
-
]
|
|
1949
|
-
});
|
|
1950
|
-
return fieldProjection2;
|
|
1951
|
-
}, [
|
|
1952
|
-
model,
|
|
1953
|
-
editing
|
|
1954
|
-
]);
|
|
1955
|
-
const handleEnter = useCallback4(async (value) => {
|
|
1956
|
-
if (!model || !editing) {
|
|
1957
|
-
return;
|
|
1958
|
-
}
|
|
1959
|
-
const cell = parseCellIndex2(editing.index);
|
|
1960
|
-
const result = await model.validateCellData(cell, value);
|
|
1961
|
-
if (result.valid) {
|
|
1962
|
-
setValidationError(null);
|
|
1963
|
-
model.setCellData(cell, value);
|
|
1964
|
-
onEnter?.(cell);
|
|
1965
|
-
onFocus?.();
|
|
1966
|
-
setEditing(null);
|
|
1967
|
-
} else {
|
|
1968
|
-
setValidationError(result.error);
|
|
1969
|
-
}
|
|
1970
|
-
}, [
|
|
1971
|
-
model,
|
|
1972
|
-
editing,
|
|
1973
|
-
onEnter,
|
|
1974
|
-
onFocus,
|
|
1975
|
-
setEditing
|
|
1976
|
-
]);
|
|
1977
|
-
const handleBlur = useCallback4(async (value) => {
|
|
1978
|
-
if (!model || !editing) {
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
if (suppressNextBlur.current) {
|
|
1982
|
-
suppressNextBlur.current = false;
|
|
1983
|
-
}
|
|
1984
|
-
}, [
|
|
1985
|
-
model,
|
|
1986
|
-
editing
|
|
1987
|
-
]);
|
|
1988
|
-
const handleClose = useCallback4(async (value, event) => {
|
|
1989
|
-
if (!model || !editing || !fieldProjection) {
|
|
1990
|
-
return;
|
|
1991
|
-
}
|
|
1992
|
-
const cell = parseCellIndex2(editing.index);
|
|
1993
|
-
if (value !== void 0) {
|
|
1994
|
-
const result = await model.validateCellData(cell, value);
|
|
1995
|
-
if (result.valid) {
|
|
1996
|
-
setValidationError(null);
|
|
1997
|
-
model.setCellData(cell, value);
|
|
1998
|
-
setEditing(null);
|
|
1999
|
-
onEnter?.(cell);
|
|
2000
|
-
if (event && onFocus) {
|
|
2001
|
-
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
2002
|
-
}
|
|
2003
|
-
} else {
|
|
2004
|
-
setValidationError(result.error);
|
|
2005
|
-
}
|
|
2006
|
-
} else {
|
|
516
|
+
const cell = parseCellIndex2(editing.index);
|
|
517
|
+
if (value !== void 0) {
|
|
518
|
+
const result = await model.validateCellData(cell, value);
|
|
519
|
+
if (result.valid) {
|
|
520
|
+
suppressNextBlur.current = true;
|
|
2007
521
|
setValidationError(null);
|
|
522
|
+
model.setCellData(cell, value);
|
|
2008
523
|
setEditing(null);
|
|
524
|
+
onSave?.();
|
|
2009
525
|
if (event && onFocus) {
|
|
2010
|
-
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
526
|
+
onFocus(determineNavigationAxis(event), determineNavigationDelta(event), cell);
|
|
2011
527
|
}
|
|
528
|
+
} else {
|
|
529
|
+
setValidationError(result.error);
|
|
530
|
+
setValidationVariant("error");
|
|
2012
531
|
}
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
]);
|
|
2021
|
-
const extension = useMemo4(() => {
|
|
2022
|
-
if (!fieldProjection) {
|
|
2023
|
-
return [];
|
|
2024
|
-
}
|
|
2025
|
-
const extension2 = [
|
|
2026
|
-
editorKeys({
|
|
2027
|
-
onClose: handleClose,
|
|
2028
|
-
...editing?.initialContent && {
|
|
2029
|
-
onNav: handleClose
|
|
2030
|
-
}
|
|
2031
|
-
})
|
|
2032
|
-
];
|
|
2033
|
-
const format = fieldProjection.props.format;
|
|
2034
|
-
if (format === FormatEnum5.SingleSelect || format === FormatEnum5.MultiSelect) {
|
|
2035
|
-
extension2.push(createMarkdownExtensions({
|
|
2036
|
-
themeMode
|
|
2037
|
-
}));
|
|
2038
|
-
const options = fieldProjection.props.options || [];
|
|
2039
|
-
const mode = format === FormatEnum5.SingleSelect ? "single-select" : "multi-select";
|
|
2040
|
-
extension2.push(tagPickerExtension({
|
|
2041
|
-
mode,
|
|
2042
|
-
inGrid: true,
|
|
2043
|
-
onSearch: (text, selectedIds) => {
|
|
2044
|
-
return options.filter((option) => selectedIds.indexOf(option.id) === -1 && (text.length === 0 || option.title.toLowerCase().includes(text.toLowerCase()))).map((option) => ({
|
|
2045
|
-
id: option.id,
|
|
2046
|
-
label: option.title,
|
|
2047
|
-
hue: option.color
|
|
2048
|
-
}));
|
|
2049
|
-
},
|
|
2050
|
-
onUpdate: (ids) => {
|
|
2051
|
-
if (model && editing) {
|
|
2052
|
-
if (ids.length === 0) {
|
|
2053
|
-
return;
|
|
2054
|
-
}
|
|
2055
|
-
if (mode === "single-select") {
|
|
2056
|
-
void handleEnter(ids[0]);
|
|
2057
|
-
} else {
|
|
2058
|
-
void handleEnter(ids);
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
}));
|
|
532
|
+
} else {
|
|
533
|
+
suppressNextBlur.current = true;
|
|
534
|
+
setValidationError(null);
|
|
535
|
+
setEditing(null);
|
|
536
|
+
onSave?.();
|
|
537
|
+
if (event && onFocus) {
|
|
538
|
+
onFocus(determineNavigationAxis(event), determineNavigationDelta(event));
|
|
2063
539
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
} else {
|
|
2083
|
-
void handleEnter(data);
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
})
|
|
2088
|
-
]);
|
|
2089
|
-
break;
|
|
2090
|
-
}
|
|
540
|
+
}
|
|
541
|
+
}, [
|
|
542
|
+
model,
|
|
543
|
+
editing,
|
|
544
|
+
onFocus,
|
|
545
|
+
fieldProjection,
|
|
546
|
+
setEditing,
|
|
547
|
+
onSave
|
|
548
|
+
]);
|
|
549
|
+
const extensions = useMemo2(() => {
|
|
550
|
+
if (!fieldProjection) {
|
|
551
|
+
return [];
|
|
552
|
+
}
|
|
553
|
+
const extensions2 = [
|
|
554
|
+
editorKeys({
|
|
555
|
+
onClose: handleClose,
|
|
556
|
+
...editing?.initialContent && {
|
|
557
|
+
onNav: handleClose
|
|
2091
558
|
}
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
editing,
|
|
2098
|
-
fieldProjection,
|
|
2099
|
-
handleClose,
|
|
2100
|
-
themeMode
|
|
2101
|
-
]);
|
|
2102
|
-
const getCellContent = useCallback4(() => {
|
|
2103
|
-
if (model && editing) {
|
|
559
|
+
})
|
|
560
|
+
];
|
|
561
|
+
if (model && editing) {
|
|
562
|
+
extensions2.push(EditorView.updateListener.of(debounce((update) => {
|
|
563
|
+
const content = update.state.doc.toString();
|
|
2104
564
|
const cell = parseCellIndex2(editing.index);
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
const options = fieldProjection2.props.options || [];
|
|
2112
|
-
if (fieldProjection2.props.format === FormatEnum5.MultiSelect && Array.isArray(value2)) {
|
|
2113
|
-
const tagItems = value2.map((id) => {
|
|
2114
|
-
const option = options.find((o) => o.id === id);
|
|
2115
|
-
if (option) {
|
|
2116
|
-
return {
|
|
2117
|
-
id,
|
|
2118
|
-
label: option.title,
|
|
2119
|
-
hue: option.color
|
|
2120
|
-
};
|
|
2121
|
-
}
|
|
2122
|
-
return void 0;
|
|
2123
|
-
}).filter((item) => item !== void 0);
|
|
2124
|
-
return createLinks(tagItems);
|
|
2125
|
-
} else {
|
|
2126
|
-
const option = options.find((o) => o.id === value2);
|
|
2127
|
-
if (option) {
|
|
2128
|
-
const tagItem = {
|
|
2129
|
-
id: value2,
|
|
2130
|
-
label: option.title,
|
|
2131
|
-
hue: option.color
|
|
2132
|
-
};
|
|
2133
|
-
return createLinks([
|
|
2134
|
-
tagItem
|
|
2135
|
-
]);
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
565
|
+
void model.validateCellData(cell, content).then((result) => {
|
|
566
|
+
if (result.valid) {
|
|
567
|
+
setValidationError(null);
|
|
568
|
+
} else {
|
|
569
|
+
setValidationError(result.error);
|
|
570
|
+
setValidationVariant("error");
|
|
2138
571
|
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
572
|
+
});
|
|
573
|
+
}, 10)));
|
|
574
|
+
}
|
|
575
|
+
return extensions2;
|
|
576
|
+
}, [
|
|
577
|
+
model,
|
|
578
|
+
modals,
|
|
579
|
+
editing,
|
|
580
|
+
fieldProjection,
|
|
581
|
+
handleClose
|
|
582
|
+
]);
|
|
583
|
+
const getCellContent = useCallback2(() => {
|
|
584
|
+
if (model && editing) {
|
|
585
|
+
const cell = parseCellIndex2(editing.index);
|
|
586
|
+
const value = model.getCellData(cell);
|
|
587
|
+
return value !== void 0 ? String(value) : "";
|
|
588
|
+
}
|
|
589
|
+
}, [
|
|
590
|
+
model,
|
|
591
|
+
editing
|
|
592
|
+
]);
|
|
593
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(CellValidationMessage, {
|
|
594
|
+
validationError,
|
|
595
|
+
variant: validationVariant,
|
|
596
|
+
__gridScope
|
|
597
|
+
}), /* @__PURE__ */ React3.createElement(GridCellEditor, {
|
|
598
|
+
extensions,
|
|
599
|
+
slots: {
|
|
600
|
+
content: {
|
|
601
|
+
className: "!py-(--dx-grid-cell-editor-padding-block)"
|
|
2143
602
|
}
|
|
2144
|
-
},
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(CellValidationMessage, {
|
|
2149
|
-
validationError: _validationError,
|
|
2150
|
-
__gridScope
|
|
2151
|
-
}), /* @__PURE__ */ React7.createElement(GridCellEditor, {
|
|
2152
|
-
extension,
|
|
2153
|
-
getCellContent,
|
|
2154
|
-
onBlur: handleBlur
|
|
2155
|
-
}));
|
|
2156
|
-
} finally {
|
|
2157
|
-
_effect.f();
|
|
2158
|
-
}
|
|
603
|
+
},
|
|
604
|
+
getCellContent,
|
|
605
|
+
onBlur: handleBlur
|
|
606
|
+
}));
|
|
2159
607
|
};
|
|
2160
608
|
var determineNavigationAxis = ({ key }) => {
|
|
2161
609
|
switch (key) {
|
|
@@ -2182,508 +630,561 @@ var determineNavigationDelta = ({ key, shift }) => {
|
|
|
2182
630
|
return shift ? -1 : 1;
|
|
2183
631
|
};
|
|
2184
632
|
|
|
2185
|
-
//
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
633
|
+
// src/components/Table/ColumnActionsMenu.tsx
|
|
634
|
+
import { useAtomValue } from "@effect-atom/atom-react";
|
|
635
|
+
import React4 from "react";
|
|
636
|
+
import { DropdownMenu, useTranslation } from "@dxos/react-ui";
|
|
637
|
+
import { translationKey as translationKey2 } from "#translations";
|
|
638
|
+
var ColumnActionsMenu = ({ model, modals }) => {
|
|
639
|
+
const { t } = useTranslation(translationKey2);
|
|
640
|
+
const state = useAtomValue(modals.state);
|
|
641
|
+
if (state?.type !== "column") {
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
const currentSort = model.getSorting();
|
|
645
|
+
const isCurrentColumnSorted = currentSort?.fieldId === state.fieldId;
|
|
646
|
+
return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, {
|
|
647
|
+
modal: false,
|
|
648
|
+
open: true,
|
|
649
|
+
onOpenChange: modals.close
|
|
650
|
+
}, /* @__PURE__ */ React4.createElement(DropdownMenu.VirtualTrigger, {
|
|
651
|
+
virtualRef: modals.trigger
|
|
652
|
+
}), /* @__PURE__ */ React4.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Viewport, null, (!isCurrentColumnSorted || currentSort?.direction === "asc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
653
|
+
"data-testid": "column-sort-descending",
|
|
654
|
+
onClick: () => model.setSort(state.fieldId, "desc")
|
|
655
|
+
}, t("column-action-sort-descending.menu")), (!isCurrentColumnSorted || currentSort?.direction === "desc") && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
656
|
+
"data-testid": "column-sort-ascending",
|
|
657
|
+
onClick: () => model.setSort(state.fieldId, "asc")
|
|
658
|
+
}, t("column-action-sort-ascending.menu")), isCurrentColumnSorted && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
659
|
+
"data-testid": "column-clear-sort",
|
|
660
|
+
onClick: () => model.clearSort()
|
|
661
|
+
}, t("column-action-clear-sorting.menu")), model.getColumnCount() > 1 && model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
662
|
+
"data-testid": "column-delete",
|
|
663
|
+
onClick: () => model.deleteColumn(state.fieldId)
|
|
664
|
+
}, t("column-action-delete.menu")), model.features.schemaEditable && /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
|
|
665
|
+
"data-testid": "column-settings",
|
|
666
|
+
onClick: () => modals.openColumnSettings()
|
|
667
|
+
}, t("column-action-settings.menu"))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
|
|
2197
668
|
};
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
669
|
+
|
|
670
|
+
// src/components/Table/ColumnSettings.tsx
|
|
671
|
+
import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
|
|
672
|
+
import React5, { useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo3, useState as useState3 } from "react";
|
|
673
|
+
import { Popover as Popover2 } from "@dxos/react-ui";
|
|
674
|
+
import { FieldEditor } from "@dxos/react-ui-form";
|
|
675
|
+
var ColumnSettings = ({ registry, model, modals, onNewColumn }) => {
|
|
676
|
+
const [newField, setNewField] = useState3();
|
|
677
|
+
const state = useAtomValue2(modals.state);
|
|
678
|
+
useEffect2(() => {
|
|
679
|
+
if (state?.type === "columnSettings" && state.mode.type === "create" && model?.projection) {
|
|
680
|
+
setNewField(model.projection.createFieldProjection());
|
|
681
|
+
requestAnimationFrame(() => {
|
|
682
|
+
onNewColumn();
|
|
683
|
+
});
|
|
684
|
+
} else {
|
|
685
|
+
setNewField(void 0);
|
|
686
|
+
}
|
|
687
|
+
}, [
|
|
688
|
+
model?.projection,
|
|
689
|
+
state
|
|
690
|
+
]);
|
|
691
|
+
const existingField = useMemo3(() => {
|
|
692
|
+
if (state?.type === "columnSettings") {
|
|
693
|
+
const { mode } = state;
|
|
694
|
+
if (mode.type === "edit") {
|
|
695
|
+
return model?.projection?.getFields().find((f) => f.id === mode.fieldId);
|
|
2221
696
|
}
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
697
|
+
}
|
|
698
|
+
return void 0;
|
|
699
|
+
}, [
|
|
700
|
+
model?.projection,
|
|
701
|
+
state
|
|
702
|
+
]);
|
|
703
|
+
const field = existingField ?? newField;
|
|
704
|
+
const handleSave = useCallback3(() => {
|
|
705
|
+
modals.close();
|
|
706
|
+
}, [
|
|
707
|
+
modals
|
|
708
|
+
]);
|
|
709
|
+
const handleCancel = useCallback3(() => {
|
|
710
|
+
if (state?.type === "columnSettings" && state.mode.type === "create" && newField) {
|
|
711
|
+
model?.projection.deleteFieldProjection(newField.id);
|
|
712
|
+
}
|
|
713
|
+
}, [
|
|
714
|
+
model?.projection,
|
|
715
|
+
state,
|
|
716
|
+
newField
|
|
717
|
+
]);
|
|
718
|
+
if (!model?.projection || !field) {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
return /* @__PURE__ */ React5.createElement(Popover2.Root, {
|
|
722
|
+
modal: false,
|
|
723
|
+
open: state?.type === "columnSettings"
|
|
724
|
+
}, /* @__PURE__ */ React5.createElement(Popover2.VirtualTrigger, {
|
|
725
|
+
virtualRef: modals.trigger
|
|
726
|
+
}), /* @__PURE__ */ React5.createElement(Popover2.Portal, null, /* @__PURE__ */ React5.createElement(Popover2.Content, {
|
|
727
|
+
classNames: "md:w-64"
|
|
728
|
+
}, /* @__PURE__ */ React5.createElement(Popover2.Viewport, null, /* @__PURE__ */ React5.createElement(FieldEditor, {
|
|
729
|
+
projection: model.projection,
|
|
730
|
+
field,
|
|
731
|
+
registry,
|
|
732
|
+
onSave: handleSave,
|
|
733
|
+
onCancel: handleCancel
|
|
734
|
+
})), /* @__PURE__ */ React5.createElement(Popover2.Arrow, null))));
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
// src/components/Table/RowActionsMenu.tsx
|
|
738
|
+
import { useAtomValue as useAtomValue3 } from "@effect-atom/atom-react";
|
|
739
|
+
import React6 from "react";
|
|
740
|
+
import { DropdownMenu as DropdownMenu2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
|
|
741
|
+
import { translationKey as translationKey3 } from "#translations";
|
|
742
|
+
var RowActionsMenu = ({ model, modals }) => {
|
|
743
|
+
const { t } = useTranslation2(translationKey3);
|
|
744
|
+
const hasSelection = model.selection.hasSelection;
|
|
745
|
+
const state = useAtomValue3(modals.state);
|
|
746
|
+
if (state?.type !== "row") {
|
|
747
|
+
return null;
|
|
748
|
+
}
|
|
749
|
+
return /* @__PURE__ */ React6.createElement(DropdownMenu2.Root, {
|
|
750
|
+
modal: false,
|
|
751
|
+
open: true,
|
|
752
|
+
onOpenChange: modals.close
|
|
753
|
+
}, /* @__PURE__ */ React6.createElement(DropdownMenu2.VirtualTrigger, {
|
|
754
|
+
virtualRef: modals.trigger
|
|
755
|
+
}), /* @__PURE__ */ React6.createElement(DropdownMenu2.Content, null, /* @__PURE__ */ React6.createElement(DropdownMenu2.Viewport, null, model.rowActions?.length > 0 && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(DropdownMenu2.Group, null, model.rowActions?.map((action) => /* @__PURE__ */ React6.createElement(DropdownMenu2.Item, {
|
|
756
|
+
key: action.id,
|
|
757
|
+
"data-testid": `row-action-${action.id}`,
|
|
758
|
+
onClick: () => {
|
|
759
|
+
modals.close();
|
|
760
|
+
model.handleRowAction(action.id, state.rowIndex);
|
|
761
|
+
}
|
|
762
|
+
}, toLocalizedString(action.label, t)))), /* @__PURE__ */ React6.createElement(DropdownMenu2.Separator, null)), model.features.dataEditable !== false && /* @__PURE__ */ React6.createElement(DropdownMenu2.Item, {
|
|
763
|
+
"data-testid": "row-menu-delete",
|
|
764
|
+
onClick: () => model.deleteRow(state.rowIndex)
|
|
765
|
+
}, t(hasSelection ? "bulk-delete-row.label" : "delete-row.label"))), /* @__PURE__ */ React6.createElement(DropdownMenu2.Arrow, null)));
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
// src/components/Table/TableContent.tsx
|
|
769
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/react-ui-table/src/components/Table/TableContent.tsx";
|
|
770
|
+
var columnDefault = {
|
|
771
|
+
grid: {
|
|
772
|
+
minSize: 80,
|
|
773
|
+
maxSize: 640
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
var rowDefault = {
|
|
777
|
+
frozenRowsStart: {
|
|
778
|
+
readonly: true,
|
|
779
|
+
focusUnfurl: false
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
var emptyColumnMeta = Atom2.make({
|
|
783
|
+
grid: {}
|
|
784
|
+
});
|
|
785
|
+
var emptyRowsAtom = Atom2.make([]);
|
|
786
|
+
var emptyCellUpdateAtom = Atom2.make(0);
|
|
787
|
+
var TABLE_CONTENT_NAME = "Table.Content";
|
|
788
|
+
var TableContent = composable(({ schema, model, presentation, ignoreAttention, onCreate, onRowClick, testId, ...props }, forwardedRef) => {
|
|
789
|
+
const registry = useContext(RegistryContext);
|
|
790
|
+
const [dxGrid, setDxGrid] = useState4(null);
|
|
791
|
+
const { hasAttention } = useAttention(model?.id ?? "table");
|
|
792
|
+
const modals = useMemo4(() => new ModalController(registry), [
|
|
793
|
+
registry
|
|
794
|
+
]);
|
|
795
|
+
const columnMeta = useAtomValue4(model?.columnMeta ?? emptyColumnMeta);
|
|
796
|
+
const rows = useAtomValue4(model?.rows ?? emptyRowsAtom);
|
|
797
|
+
const cellUpdateCounter = useAtomValue4(model?.cellUpdate ?? emptyCellUpdateAtom);
|
|
798
|
+
const columnCount = Object.keys(columnMeta.grid).length || model?.projection.getFields().length || 0;
|
|
799
|
+
const draftRowCount = model?.getDraftRowCount() ?? 0;
|
|
800
|
+
const frozen = useMemo4(() => {
|
|
801
|
+
const noActionColumn = model?.features.dataEditable === false && model?.features.schemaEditable === false && model.rowActions.length === 0;
|
|
802
|
+
return {
|
|
803
|
+
frozenRowsStart: 1,
|
|
804
|
+
frozenRowsEnd: Math.max(1, draftRowCount),
|
|
805
|
+
frozenColsStart: model?.features.selection.enabled ? 1 : 0,
|
|
806
|
+
frozenColsEnd: noActionColumn ? 0 : 1
|
|
807
|
+
};
|
|
808
|
+
}, [
|
|
809
|
+
model,
|
|
810
|
+
draftRowCount
|
|
811
|
+
]);
|
|
812
|
+
const getCells = useCallback4((range, plane) => presentation?.getCells(range, plane) ?? {}, [
|
|
813
|
+
presentation
|
|
814
|
+
]);
|
|
815
|
+
useEffect3(() => {
|
|
816
|
+
if (!dxGrid || !presentation) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
dxGrid.getCells = getCells;
|
|
820
|
+
}, [
|
|
821
|
+
dxGrid,
|
|
822
|
+
presentation,
|
|
823
|
+
getCells
|
|
824
|
+
]);
|
|
825
|
+
useEffect3(() => {
|
|
826
|
+
if (!dxGrid) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
dxGrid.updateCells(true);
|
|
830
|
+
dxGrid.requestUpdate();
|
|
831
|
+
}, [
|
|
832
|
+
dxGrid,
|
|
833
|
+
rows,
|
|
834
|
+
cellUpdateCounter
|
|
835
|
+
]);
|
|
836
|
+
const handleInsertRowResult = useCallback4((insertResult) => {
|
|
837
|
+
if (insertResult === "draft") {
|
|
838
|
+
requestAnimationFrame(() => {
|
|
839
|
+
dxGrid?.setFocus({
|
|
840
|
+
plane: "frozenRowsEnd",
|
|
841
|
+
col: 0,
|
|
842
|
+
row: 0
|
|
843
|
+
});
|
|
844
|
+
dxGrid?.refocus();
|
|
845
|
+
});
|
|
846
|
+
} else {
|
|
847
|
+
requestAnimationFrame(() => {
|
|
848
|
+
dxGrid?.setFocus({
|
|
849
|
+
plane: "grid",
|
|
850
|
+
col: 0,
|
|
851
|
+
row: model ? model.getRowCount() - 1 : 0
|
|
852
|
+
});
|
|
853
|
+
dxGrid?.refocus();
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
}, [
|
|
857
|
+
model,
|
|
858
|
+
dxGrid
|
|
859
|
+
]);
|
|
860
|
+
const handleSave = useCallback4(() => {
|
|
861
|
+
dxGrid?.updateCells(true);
|
|
862
|
+
dxGrid?.requestUpdate();
|
|
863
|
+
}, [
|
|
864
|
+
dxGrid
|
|
865
|
+
]);
|
|
866
|
+
const handleSaveDraftRow = useCallback4((rowIndex = 0) => {
|
|
867
|
+
if (model && dxGrid) {
|
|
868
|
+
const didCommitSuccessfully = model.commitDraftRow(rowIndex);
|
|
869
|
+
if (didCommitSuccessfully) {
|
|
870
|
+
requestAnimationFrame(() => {
|
|
871
|
+
dxGrid.scrollToEndRow();
|
|
872
|
+
});
|
|
2231
873
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
presentation,
|
|
2244
|
-
dxGrid
|
|
2245
|
-
]);
|
|
2246
|
-
const handleGridClick = useCallback5((event) => {
|
|
2247
|
-
const rowIndex = safeParseInt(event.target.ariaRowIndex ?? "");
|
|
2248
|
-
if (rowIndex != null) {
|
|
2249
|
-
if (onRowClick) {
|
|
874
|
+
}
|
|
875
|
+
}, [
|
|
876
|
+
model,
|
|
877
|
+
dxGrid
|
|
878
|
+
]);
|
|
879
|
+
const handleGridClick = useCallback4((event) => {
|
|
880
|
+
const cell = closestCell(event.target);
|
|
881
|
+
if (cell) {
|
|
882
|
+
const { row: rowIndex, plane } = cell;
|
|
883
|
+
if (onRowClick) {
|
|
884
|
+
if (plane === "grid") {
|
|
2250
885
|
const row = model?.getRowAt(rowIndex);
|
|
2251
886
|
row && onRowClick(row);
|
|
887
|
+
} else {
|
|
888
|
+
onRowClick(cell);
|
|
2252
889
|
}
|
|
2253
|
-
if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
|
|
2254
|
-
model.selection.toggleSelectionForRowIndex(rowIndex);
|
|
2255
|
-
}
|
|
2256
890
|
}
|
|
2257
|
-
if (
|
|
891
|
+
if (model?.features.selection.enabled && model?.selection.selectionMode === "single") {
|
|
892
|
+
model.selection.toggleSelectionForRowIndex(rowIndex);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (!modals) {
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const buttonSelector = Object.values(tableButtons).map((button) => `button[${button.attr}]`).join(",");
|
|
899
|
+
const tableButtonElement = event.target.closest(buttonSelector);
|
|
900
|
+
if (tableButtonElement) {
|
|
901
|
+
const button = Object.values(tableButtons).find((btn) => tableButtonElement.hasAttribute(btn.attr));
|
|
902
|
+
if (!button) {
|
|
2258
903
|
return;
|
|
2259
904
|
}
|
|
2260
|
-
|
|
2261
|
-
const
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
905
|
+
modals.setTrigger(tableButtonElement);
|
|
906
|
+
const data = button.getData(tableButtonElement);
|
|
907
|
+
switch (data.type) {
|
|
908
|
+
case "rowMenu": {
|
|
909
|
+
modals.showRowMenu(data.rowIndex);
|
|
910
|
+
break;
|
|
2266
911
|
}
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
case "rowMenu": {
|
|
2271
|
-
modals.showRowMenu(data.rowIndex);
|
|
2272
|
-
break;
|
|
2273
|
-
}
|
|
2274
|
-
case "columnSettings": {
|
|
2275
|
-
modals.showColumnMenu(data.fieldId);
|
|
2276
|
-
break;
|
|
2277
|
-
}
|
|
2278
|
-
case "newColumn": {
|
|
2279
|
-
modals.showColumnCreator();
|
|
2280
|
-
break;
|
|
2281
|
-
}
|
|
2282
|
-
case "sort": {
|
|
2283
|
-
model?.sorting?.toggleSort(data.fieldId);
|
|
2284
|
-
break;
|
|
2285
|
-
}
|
|
912
|
+
case "columnSettings": {
|
|
913
|
+
modals.showColumnMenu(data.fieldId);
|
|
914
|
+
break;
|
|
2286
915
|
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
const controlElement = event.target.closest(controlSelector);
|
|
2291
|
-
if (controlElement) {
|
|
2292
|
-
const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
|
|
2293
|
-
if (!control) {
|
|
2294
|
-
return;
|
|
916
|
+
case "newColumn": {
|
|
917
|
+
modals.showColumnCreator();
|
|
918
|
+
break;
|
|
2295
919
|
}
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
if (data.header) {
|
|
2300
|
-
model?.selection.setSelection(model.selection.allRowsSeleted.value ? "none" : "all");
|
|
2301
|
-
} else {
|
|
2302
|
-
model?.selection.toggleSelectionForRowIndex(data.rowIndex);
|
|
2303
|
-
}
|
|
2304
|
-
break;
|
|
2305
|
-
}
|
|
2306
|
-
case "switch": {
|
|
2307
|
-
if (model) {
|
|
2308
|
-
model.updateCellData({
|
|
2309
|
-
row: data.rowIndex,
|
|
2310
|
-
col: data.colIndex
|
|
2311
|
-
}, (value) => !value);
|
|
2312
|
-
}
|
|
2313
|
-
break;
|
|
2314
|
-
}
|
|
920
|
+
case "sort": {
|
|
921
|
+
model?.toggleSort(data.fieldId);
|
|
922
|
+
break;
|
|
2315
923
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
modals
|
|
2320
|
-
]);
|
|
2321
|
-
const handleFocus = useCallback5((increment, delta) => {
|
|
2322
|
-
if (dxGrid) {
|
|
2323
|
-
dxGrid.refocus(increment, delta);
|
|
2324
|
-
}
|
|
2325
|
-
}, [
|
|
2326
|
-
dxGrid
|
|
2327
|
-
]);
|
|
2328
|
-
const handleEnter = useCallback5((cell) => {
|
|
2329
|
-
if (!model?.features.dataEditable) {
|
|
2330
|
-
return;
|
|
2331
|
-
}
|
|
2332
|
-
if (model && cell.row === model.getRowCount() - 1) {
|
|
2333
|
-
model.insertRow(cell.row);
|
|
2334
|
-
if (dxGrid) {
|
|
2335
|
-
requestAnimationFrame(() => {
|
|
2336
|
-
dxGrid?.scrollToRow(cell.row + 1);
|
|
2337
|
-
dxGrid?.refocus("row", 1);
|
|
2338
|
-
});
|
|
924
|
+
case "saveDraftRow": {
|
|
925
|
+
handleSaveDraftRow();
|
|
926
|
+
break;
|
|
2339
927
|
}
|
|
2340
928
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
}
|
|
2349
|
-
const cell = closestCell(event.target);
|
|
2350
|
-
if (!model || !cell) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
const controlSelector = Object.values(tableControls).map((control) => `input[${control.attr}]`).join(",");
|
|
932
|
+
const controlElement = event.target.closest(controlSelector);
|
|
933
|
+
if (controlElement) {
|
|
934
|
+
const control = Object.values(tableControls).find((ctrl) => controlElement.hasAttribute(ctrl.attr));
|
|
935
|
+
if (!control) {
|
|
2351
936
|
return;
|
|
2352
937
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
case "
|
|
2356
|
-
|
|
938
|
+
const data = control.getData(controlElement);
|
|
939
|
+
switch (data.type) {
|
|
940
|
+
case "checkbox": {
|
|
941
|
+
if (data.header) {
|
|
942
|
+
model?.selection.setSelection(model.selection.allRowsSelected ? "none" : "all");
|
|
943
|
+
} else {
|
|
944
|
+
model?.selection.toggleSelectionForRowIndex(data.rowIndex);
|
|
945
|
+
}
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
case "switch": {
|
|
949
|
+
if (model) {
|
|
950
|
+
model.updateCellData({
|
|
951
|
+
row: data.rowIndex,
|
|
952
|
+
col: data.colIndex
|
|
953
|
+
}, (value) => !value);
|
|
954
|
+
}
|
|
2357
955
|
break;
|
|
2358
956
|
}
|
|
2359
957
|
}
|
|
2360
|
-
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
}, [
|
|
2376
|
-
hasAttention,
|
|
2377
|
-
ignoreAttention
|
|
2378
|
-
]);
|
|
2379
|
-
const handleNewColumn = useCallback5(() => {
|
|
2380
|
-
const columns = model?.getColumnCount();
|
|
2381
|
-
if (dxGrid && columns) {
|
|
2382
|
-
dxGrid.scrollToColumn(columns - 1);
|
|
958
|
+
}
|
|
959
|
+
}, [
|
|
960
|
+
model,
|
|
961
|
+
modals,
|
|
962
|
+
dxGrid
|
|
963
|
+
]);
|
|
964
|
+
const handleFocus = useCallback4((increment, delta, cell) => {
|
|
965
|
+
if (dxGrid && model) {
|
|
966
|
+
if (cell?.plane === "grid" && cell?.row >= model.getRowCount() - 1 && increment !== "col") {
|
|
967
|
+
handleInsertRowResult(draftRowCount < 1 ? model.insertRow() : "final");
|
|
968
|
+
} else if (cell?.plane === "frozenRowsEnd" && increment === "row") {
|
|
969
|
+
handleSaveDraftRow(cell.row);
|
|
970
|
+
handleInsertRowResult(model.insertRow());
|
|
971
|
+
} else {
|
|
972
|
+
dxGrid.refocus(increment, delta);
|
|
2383
973
|
}
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
974
|
+
}
|
|
975
|
+
}, [
|
|
976
|
+
dxGrid,
|
|
977
|
+
model
|
|
978
|
+
]);
|
|
979
|
+
const handleKeyDown = useCallback4((event) => {
|
|
980
|
+
if (!model?.features.dataEditable) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
const cell = closestCell(event.target);
|
|
984
|
+
if (!model || !cell) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (event.metaKey || event.ctrlKey) {
|
|
988
|
+
switch (event.key) {
|
|
989
|
+
case "c": {
|
|
990
|
+
try {
|
|
991
|
+
const cellData = model.getCellData(cell);
|
|
992
|
+
const textContent = cellData?.toString() ?? "";
|
|
993
|
+
void navigator.clipboard.writeText(textContent);
|
|
994
|
+
event.preventDefault();
|
|
995
|
+
} catch (error) {
|
|
996
|
+
log.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 262, S: void 0 });
|
|
997
|
+
}
|
|
998
|
+
break;
|
|
2406
999
|
}
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
}
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
1000
|
+
case "v": {
|
|
1001
|
+
event.preventDefault();
|
|
1002
|
+
void navigator.clipboard.readText().then((clipboardText) => {
|
|
1003
|
+
try {
|
|
1004
|
+
model.setCellData(cell, String2.trim(clipboardText).replace(/[\n\r]+/, " "));
|
|
1005
|
+
handleSave();
|
|
1006
|
+
} catch {
|
|
1007
|
+
const cellElement = event.target.closest('[data-dx-grid-action="cell"]');
|
|
1008
|
+
if (cellElement) {
|
|
1009
|
+
const rect = cellElement.getBoundingClientRect();
|
|
1010
|
+
const editRequest = new DxEditRequest({
|
|
1011
|
+
cellIndex: `${cell.plane},${cell.col},${cell.row}`,
|
|
1012
|
+
cellBox: {
|
|
1013
|
+
insetInlineStart: rect.left,
|
|
1014
|
+
insetBlockStart: rect.top,
|
|
1015
|
+
inlineSize: rect.width,
|
|
1016
|
+
blockSize: rect.height
|
|
1017
|
+
},
|
|
1018
|
+
cellElement,
|
|
1019
|
+
initialContent: clipboardText
|
|
1020
|
+
});
|
|
1021
|
+
cellElement.dispatchEvent(editRequest);
|
|
1022
|
+
}
|
|
2426
1023
|
}
|
|
2427
|
-
|
|
1024
|
+
});
|
|
1025
|
+
break;
|
|
2428
1026
|
}
|
|
2429
1027
|
}
|
|
2430
|
-
return [];
|
|
2431
|
-
}, [
|
|
2432
|
-
model,
|
|
2433
|
-
client,
|
|
2434
|
-
t
|
|
2435
|
-
]);
|
|
2436
|
-
if (!model || !modals) {
|
|
2437
|
-
return /* @__PURE__ */ React8.createElement("span", {
|
|
2438
|
-
role: "none",
|
|
2439
|
-
className: "attention-surface"
|
|
2440
|
-
});
|
|
2441
1028
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
className: mx2("[--dx-grid-base:var(--baseSurface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
|
|
2453
|
-
frozen,
|
|
2454
|
-
// getCells={getCells}
|
|
2455
|
-
columns: model.columnMeta.value,
|
|
2456
|
-
limitRows: model.getRowCount() ?? 0,
|
|
2457
|
-
limitColumns: model.view?.fields?.length ?? 0,
|
|
2458
|
-
overscroll: "trap",
|
|
2459
|
-
onAxisResize: handleAxisResize,
|
|
2460
|
-
onClick: handleGridClick,
|
|
2461
|
-
onKeyDown: handleKeyDown,
|
|
2462
|
-
onWheelCapture: handleWheel,
|
|
2463
|
-
ref: setDxGrid
|
|
2464
|
-
}), /* @__PURE__ */ React8.createElement(RowActionsMenu, {
|
|
2465
|
-
model,
|
|
2466
|
-
modals
|
|
2467
|
-
}), /* @__PURE__ */ React8.createElement(ColumnActionsMenu, {
|
|
2468
|
-
model,
|
|
2469
|
-
modals
|
|
2470
|
-
}), /* @__PURE__ */ React8.createElement(ColumnSettings, {
|
|
2471
|
-
model,
|
|
2472
|
-
modals,
|
|
2473
|
-
onNewColumn: handleNewColumn
|
|
2474
|
-
}), /* @__PURE__ */ React8.createElement(CreateRefPanel, {
|
|
2475
|
-
model,
|
|
2476
|
-
modals
|
|
2477
|
-
}));
|
|
2478
|
-
} finally {
|
|
2479
|
-
_effect.f();
|
|
2480
|
-
}
|
|
2481
|
-
});
|
|
2482
|
-
var Table = {
|
|
2483
|
-
Root: TableRoot,
|
|
2484
|
-
Main: TableMain
|
|
2485
|
-
};
|
|
2486
|
-
|
|
2487
|
-
// packages/ui/react-ui-table/src/components/Table/DynamicTable.tsx
|
|
2488
|
-
import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
|
|
2489
|
-
import React9, { useRef as useRef3, useMemo as useMemo6, useCallback as useCallback6 } from "react";
|
|
2490
|
-
import { useDefaultValue } from "@dxos/react-ui";
|
|
2491
|
-
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
2492
|
-
|
|
2493
|
-
// packages/ui/react-ui-table/src/hooks/useTableModel.ts
|
|
2494
|
-
import { useSignals as _useSignals9 } from "@preact-signals/safe-react/tracking";
|
|
2495
|
-
import { effect as effect3 } from "@preact/signals-core";
|
|
2496
|
-
import orderBy2 from "lodash.orderby";
|
|
2497
|
-
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
2498
|
-
import { fullyQualifiedId, getSpace } from "@dxos/react-client/echo";
|
|
2499
|
-
import { useSelectionActions } from "@dxos/react-ui-attention";
|
|
2500
|
-
import { isNonNullable } from "@dxos/util";
|
|
2501
|
-
var useTableModel = ({ table, projection, rows, rowActions, features, onSelectionChanged, onRowAction, ...props }) => {
|
|
2502
|
-
var _effect = _useSignals9();
|
|
2503
|
-
try {
|
|
2504
|
-
const [model, setModel] = useState4();
|
|
2505
|
-
useEffect4(() => {
|
|
2506
|
-
if (!table || !projection) {
|
|
2507
|
-
return;
|
|
2508
|
-
}
|
|
2509
|
-
let model2;
|
|
2510
|
-
const t = setTimeout(async () => {
|
|
2511
|
-
model2 = new TableModel({
|
|
2512
|
-
id: fullyQualifiedId(table),
|
|
2513
|
-
space: getSpace(table),
|
|
2514
|
-
view: table.view?.target,
|
|
2515
|
-
projection,
|
|
2516
|
-
features,
|
|
2517
|
-
rowActions,
|
|
2518
|
-
onRowAction,
|
|
2519
|
-
...props
|
|
2520
|
-
});
|
|
2521
|
-
await model2.open();
|
|
2522
|
-
setModel(model2);
|
|
2523
|
-
});
|
|
2524
|
-
return () => {
|
|
2525
|
-
clearTimeout(t);
|
|
2526
|
-
void model2?.close();
|
|
2527
|
-
};
|
|
2528
|
-
}, [
|
|
2529
|
-
table,
|
|
2530
|
-
projection,
|
|
2531
|
-
table?.view?.target,
|
|
2532
|
-
features,
|
|
2533
|
-
rowActions
|
|
2534
|
-
]);
|
|
2535
|
-
useEffect4(() => {
|
|
2536
|
-
if (rows) {
|
|
2537
|
-
const sortedRows = orderBy2(rows, [
|
|
2538
|
-
(row) => String(row.id)
|
|
2539
|
-
], [
|
|
2540
|
-
"asc"
|
|
2541
|
-
]);
|
|
2542
|
-
model?.setRows(sortedRows);
|
|
2543
|
-
}
|
|
2544
|
-
}, [
|
|
2545
|
-
model,
|
|
2546
|
-
rows
|
|
2547
|
-
]);
|
|
2548
|
-
const { multiSelect, clear } = useSelectionActions([
|
|
2549
|
-
table?.id,
|
|
2550
|
-
table?.view?.target?.query.typename
|
|
2551
|
-
].filter(isNonNullable));
|
|
2552
|
-
useEffect4(() => {
|
|
2553
|
-
if (!model) {
|
|
2554
|
-
return;
|
|
1029
|
+
switch (event.key) {
|
|
1030
|
+
case "Backspace":
|
|
1031
|
+
case "Delete": {
|
|
1032
|
+
try {
|
|
1033
|
+
model.setCellData(cell, void 0);
|
|
1034
|
+
event.preventDefault();
|
|
1035
|
+
handleSave();
|
|
1036
|
+
} catch {
|
|
1037
|
+
}
|
|
1038
|
+
break;
|
|
2555
1039
|
}
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
}
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
tableRef.current?.update?.(cell);
|
|
2601
|
-
}, []);
|
|
2602
|
-
const handleRowOrderChange = useCallback6(() => {
|
|
2603
|
-
tableRef.current?.update?.();
|
|
2604
|
-
}, []);
|
|
2605
|
-
const features = useDefaultValue(props.features, () => ({
|
|
2606
|
-
selection: {
|
|
2607
|
-
enabled: false
|
|
1040
|
+
}
|
|
1041
|
+
}, [
|
|
1042
|
+
model,
|
|
1043
|
+
dxGrid,
|
|
1044
|
+
handleSave
|
|
1045
|
+
]);
|
|
1046
|
+
const handleAxisResize = useCallback4((event) => {
|
|
1047
|
+
if (event.axis === "col") {
|
|
1048
|
+
const columnIndex = parseInt(event.index, 10);
|
|
1049
|
+
model?.setColumnWidth(columnIndex, event.size);
|
|
1050
|
+
}
|
|
1051
|
+
}, [
|
|
1052
|
+
model
|
|
1053
|
+
]);
|
|
1054
|
+
const handleWheel = useCallback4((event) => {
|
|
1055
|
+
if (!ignoreAttention && !hasAttention) {
|
|
1056
|
+
event.stopPropagation();
|
|
1057
|
+
}
|
|
1058
|
+
}, [
|
|
1059
|
+
hasAttention,
|
|
1060
|
+
ignoreAttention
|
|
1061
|
+
]);
|
|
1062
|
+
const handleNewColumn = useCallback4(() => {
|
|
1063
|
+
const columns = model?.getColumnCount();
|
|
1064
|
+
if (dxGrid && columns) {
|
|
1065
|
+
dxGrid.scrollToColumn(columns - 1);
|
|
1066
|
+
}
|
|
1067
|
+
}, [
|
|
1068
|
+
model,
|
|
1069
|
+
dxGrid
|
|
1070
|
+
]);
|
|
1071
|
+
const { controllerRef } = useTableContext(TABLE_CONTENT_NAME);
|
|
1072
|
+
controllerRef.current = useMemo4(() => {
|
|
1073
|
+
if (!dxGrid || !presentation) {
|
|
1074
|
+
return {};
|
|
1075
|
+
}
|
|
1076
|
+
return {
|
|
1077
|
+
update: (cell) => {
|
|
1078
|
+
if (cell) {
|
|
1079
|
+
dxGrid.updateIfWithinBounds(cell, true);
|
|
1080
|
+
} else {
|
|
1081
|
+
dxGrid.updateCells(true);
|
|
1082
|
+
dxGrid.requestUpdate();
|
|
1083
|
+
}
|
|
2608
1084
|
},
|
|
2609
|
-
|
|
2610
|
-
}
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
onRowOrderChange: handleRowOrderChange,
|
|
2619
|
-
onRowAction
|
|
2620
|
-
});
|
|
2621
|
-
const presentation = useMemo6(() => {
|
|
2622
|
-
if (model) {
|
|
2623
|
-
return new TablePresentation(model);
|
|
2624
|
-
}
|
|
2625
|
-
}, [
|
|
2626
|
-
model
|
|
2627
|
-
]);
|
|
2628
|
-
return /* @__PURE__ */ React9.createElement("div", {
|
|
2629
|
-
role: "none",
|
|
2630
|
-
className: mx3("is-full bs-full grow grid", classNames)
|
|
2631
|
-
}, /* @__PURE__ */ React9.createElement("div", {
|
|
1085
|
+
handleInsertRowResult
|
|
1086
|
+
};
|
|
1087
|
+
}, [
|
|
1088
|
+
dxGrid,
|
|
1089
|
+
model,
|
|
1090
|
+
presentation
|
|
1091
|
+
]);
|
|
1092
|
+
if (!model || !modals) {
|
|
1093
|
+
return /* @__PURE__ */ React7.createElement("span", {
|
|
2632
1094
|
role: "none",
|
|
2633
|
-
className: "
|
|
2634
|
-
}
|
|
2635
|
-
ref: tableRef,
|
|
2636
|
-
model,
|
|
2637
|
-
presentation,
|
|
2638
|
-
ignoreAttention: true,
|
|
2639
|
-
onRowClick
|
|
2640
|
-
}))));
|
|
2641
|
-
} finally {
|
|
2642
|
-
_effect.f();
|
|
1095
|
+
className: "dx-attention-surface"
|
|
1096
|
+
});
|
|
2643
1097
|
}
|
|
2644
|
-
|
|
1098
|
+
return /* @__PURE__ */ React7.createElement("div", {
|
|
1099
|
+
...composableProps(props, {
|
|
1100
|
+
classNames: "dx-container relative"
|
|
1101
|
+
}),
|
|
1102
|
+
ref: forwardedRef
|
|
1103
|
+
}, /* @__PURE__ */ React7.createElement(Grid.Root, {
|
|
1104
|
+
id: model.id ?? "table-grid"
|
|
1105
|
+
}, /* @__PURE__ */ React7.createElement(TableValueEditor, {
|
|
1106
|
+
model,
|
|
1107
|
+
modals,
|
|
1108
|
+
schema,
|
|
1109
|
+
onFocus: handleFocus,
|
|
1110
|
+
onSave: handleSave,
|
|
1111
|
+
onCreate
|
|
1112
|
+
}), /* @__PURE__ */ React7.createElement(Grid.Content, {
|
|
1113
|
+
className: mx("[--dx-grid-base:var(--base-surface)]", gridSeparatorInlineEnd, gridSeparatorBlockEnd),
|
|
1114
|
+
frozen,
|
|
1115
|
+
columns: columnMeta,
|
|
1116
|
+
columnDefault,
|
|
1117
|
+
rowDefault,
|
|
1118
|
+
limitRows: rows.length,
|
|
1119
|
+
limitColumns: columnCount,
|
|
1120
|
+
overscroll: "trap",
|
|
1121
|
+
onAxisResize: handleAxisResize,
|
|
1122
|
+
onClick: handleGridClick,
|
|
1123
|
+
onKeyDownCapture: handleKeyDown,
|
|
1124
|
+
onWheelCapture: handleWheel,
|
|
1125
|
+
...testId && {
|
|
1126
|
+
"data-testid": testId
|
|
1127
|
+
},
|
|
1128
|
+
ref: setDxGrid
|
|
1129
|
+
}), /* @__PURE__ */ React7.createElement(RowActionsMenu, {
|
|
1130
|
+
model,
|
|
1131
|
+
modals
|
|
1132
|
+
}), /* @__PURE__ */ React7.createElement(ColumnActionsMenu, {
|
|
1133
|
+
model,
|
|
1134
|
+
modals
|
|
1135
|
+
}), /* @__PURE__ */ React7.createElement(ColumnSettings, {
|
|
1136
|
+
model,
|
|
1137
|
+
modals,
|
|
1138
|
+
onNewColumn: handleNewColumn
|
|
1139
|
+
})));
|
|
1140
|
+
});
|
|
1141
|
+
TableContent.displayName = TABLE_CONTENT_NAME;
|
|
2645
1142
|
|
|
2646
|
-
//
|
|
2647
|
-
import {
|
|
2648
|
-
import {
|
|
2649
|
-
import
|
|
2650
|
-
import {
|
|
2651
|
-
import {
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
1143
|
+
// src/components/Table/TableToolbar.tsx
|
|
1144
|
+
import { Atom as Atom3, RegistryContext as RegistryContext2 } from "@effect-atom/atom-react";
|
|
1145
|
+
import React8, { useContext as useContext2, useEffect as useEffect4, useMemo as useMemo5 } from "react";
|
|
1146
|
+
import { Menu, createGapSeparator, createMenuAction, useMenuActions } from "@dxos/react-ui-menu";
|
|
1147
|
+
import { composable as composable2, composableProps as composableProps2 } from "@dxos/ui-theme";
|
|
1148
|
+
import { translationKey as translationKey4 } from "#translations";
|
|
1149
|
+
var createTableToolbarActions = ({ stateAtom, onAdd, onSave, customActions }) => Atom3.make((get) => {
|
|
1150
|
+
const nodes = [];
|
|
1151
|
+
if (onAdd) {
|
|
1152
|
+
const add = createMenuAction("add-row", onAdd, {
|
|
1153
|
+
type: "add-row",
|
|
1154
|
+
icon: "ph--plus--regular",
|
|
1155
|
+
label: [
|
|
1156
|
+
"add-row.label",
|
|
1157
|
+
{
|
|
1158
|
+
ns: translationKey4
|
|
1159
|
+
}
|
|
1160
|
+
],
|
|
1161
|
+
testId: "table.toolbar.add-row"
|
|
1162
|
+
});
|
|
1163
|
+
nodes.push(add);
|
|
1164
|
+
}
|
|
1165
|
+
if (onSave) {
|
|
1166
|
+
const state = get(stateAtom);
|
|
1167
|
+
const save = createMenuAction("save-view", onSave, {
|
|
1168
|
+
type: "save-view",
|
|
1169
|
+
icon: "ph--floppy-disk--regular",
|
|
1170
|
+
label: [
|
|
1171
|
+
"save-view.label",
|
|
1172
|
+
{
|
|
1173
|
+
ns: translationKey4
|
|
1174
|
+
}
|
|
1175
|
+
],
|
|
1176
|
+
testId: "table.toolbar.save-view",
|
|
1177
|
+
iconOnly: false,
|
|
1178
|
+
hidden: !state.viewDirty
|
|
1179
|
+
});
|
|
1180
|
+
nodes.push(save);
|
|
1181
|
+
}
|
|
2678
1182
|
const gap = createGapSeparator();
|
|
2679
|
-
|
|
2680
|
-
add,
|
|
2681
|
-
save,
|
|
2682
|
-
...gap.nodes
|
|
2683
|
-
];
|
|
1183
|
+
nodes.push(...gap.nodes);
|
|
2684
1184
|
const edges = nodes.map(({ id: target }) => ({
|
|
2685
1185
|
source: "root",
|
|
2686
|
-
target
|
|
1186
|
+
target,
|
|
1187
|
+
relation: "child"
|
|
2687
1188
|
}));
|
|
2688
1189
|
if (customActions) {
|
|
2689
1190
|
const custom = get(customActions);
|
|
@@ -2695,33 +1196,140 @@ var createTableToolbarActions = ({ state, onAdd, onSave, customActions }) => Rx.
|
|
|
2695
1196
|
edges
|
|
2696
1197
|
};
|
|
2697
1198
|
});
|
|
2698
|
-
var TableToolbar = ({
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
1199
|
+
var TableToolbar = composable2(({ attendableId, viewDirty, onAdd, onSave, customActions, ...props }, forwardedRef) => {
|
|
1200
|
+
const registry = useContext2(RegistryContext2);
|
|
1201
|
+
const stateAtom = useMemo5(() => Atom3.make({
|
|
1202
|
+
viewDirty
|
|
1203
|
+
}), []);
|
|
1204
|
+
useEffect4(() => {
|
|
1205
|
+
registry.set(stateAtom, {
|
|
2702
1206
|
viewDirty
|
|
2703
|
-
})
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
1207
|
+
});
|
|
1208
|
+
}, [
|
|
1209
|
+
registry,
|
|
1210
|
+
stateAtom,
|
|
1211
|
+
viewDirty
|
|
1212
|
+
]);
|
|
1213
|
+
const actionsCreator = useMemo5(() => createTableToolbarActions({
|
|
1214
|
+
stateAtom,
|
|
1215
|
+
onAdd,
|
|
1216
|
+
onSave,
|
|
1217
|
+
customActions
|
|
1218
|
+
}), [
|
|
1219
|
+
stateAtom,
|
|
1220
|
+
onAdd,
|
|
1221
|
+
onSave,
|
|
1222
|
+
customActions
|
|
1223
|
+
]);
|
|
1224
|
+
const menuActions = useMenuActions(actionsCreator);
|
|
1225
|
+
return /* @__PURE__ */ React8.createElement(Menu.Root, {
|
|
1226
|
+
...menuActions,
|
|
1227
|
+
attendableId
|
|
1228
|
+
}, /* @__PURE__ */ React8.createElement(Menu.Toolbar, {
|
|
1229
|
+
...composableProps2(props),
|
|
1230
|
+
ref: forwardedRef
|
|
1231
|
+
}));
|
|
1232
|
+
});
|
|
1233
|
+
TableToolbar.displayName = "TableToolbar";
|
|
1234
|
+
|
|
1235
|
+
// src/components/Table/Table.tsx
|
|
1236
|
+
var emptyColumnMeta2 = Atom4.make({
|
|
1237
|
+
grid: {}
|
|
1238
|
+
});
|
|
1239
|
+
var [TableContextProvider, useTableContext] = createContext("Table");
|
|
1240
|
+
var TABLE_ROOT_NAME = "Table.Root";
|
|
1241
|
+
var TableRoot = /* @__PURE__ */ forwardRef(({ children }, forwardedRef) => {
|
|
1242
|
+
const controllerRef = useRef3({});
|
|
1243
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
1244
|
+
update: (cell) => controllerRef.current?.update?.(cell),
|
|
1245
|
+
handleInsertRowResult: (result) => controllerRef.current?.handleInsertRowResult?.(result)
|
|
1246
|
+
}), []);
|
|
1247
|
+
return /* @__PURE__ */ React9.createElement(TableContextProvider, {
|
|
1248
|
+
controllerRef
|
|
1249
|
+
}, children);
|
|
1250
|
+
});
|
|
1251
|
+
TableRoot.displayName = TABLE_ROOT_NAME;
|
|
1252
|
+
var Table = {
|
|
1253
|
+
Root: TableRoot,
|
|
1254
|
+
Toolbar: TableToolbar,
|
|
1255
|
+
Content: TableContent
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
// src/components/Table/DynamicTable.tsx
|
|
1259
|
+
import { RegistryContext as RegistryContext3 } from "@effect-atom/atom-react";
|
|
1260
|
+
import React10, { useCallback as useCallback5, useContext as useContext3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef4, useState as useState5 } from "react";
|
|
1261
|
+
import { useDefaultValue } from "@dxos/react-ui";
|
|
1262
|
+
import { mx as mx2 } from "@dxos/ui-theme";
|
|
1263
|
+
var DynamicTable = ({ classNames, schema, name = "com.example.dynamicTable", rows, properties, jsonSchema: jsonSchemaProp, rowActions, onRowClick, onRowAction, ...props }) => {
|
|
1264
|
+
const registry = useContext3(RegistryContext3);
|
|
1265
|
+
const [dynamicTable, setDynamicTable] = useState5();
|
|
1266
|
+
const { jsonSchema } = useMemo6(() => getBaseSchema({
|
|
1267
|
+
typename: name,
|
|
1268
|
+
properties,
|
|
1269
|
+
jsonSchema: jsonSchemaProp,
|
|
1270
|
+
schema
|
|
1271
|
+
}), [
|
|
1272
|
+
name,
|
|
1273
|
+
properties,
|
|
1274
|
+
jsonSchemaProp,
|
|
1275
|
+
schema
|
|
1276
|
+
]);
|
|
1277
|
+
useEffect5(() => {
|
|
1278
|
+
setDynamicTable(makeDynamicTable({
|
|
1279
|
+
registry,
|
|
1280
|
+
jsonSchema,
|
|
1281
|
+
properties
|
|
2721
1282
|
}));
|
|
2722
|
-
}
|
|
2723
|
-
|
|
2724
|
-
|
|
1283
|
+
}, [
|
|
1284
|
+
registry,
|
|
1285
|
+
jsonSchema,
|
|
1286
|
+
properties
|
|
1287
|
+
]);
|
|
1288
|
+
const tableRef = useRef4(null);
|
|
1289
|
+
const handleCellUpdate = useCallback5((cell) => {
|
|
1290
|
+
tableRef.current?.update?.(cell);
|
|
1291
|
+
}, []);
|
|
1292
|
+
const handleRowOrderChange = useCallback5(() => {
|
|
1293
|
+
tableRef.current?.update?.();
|
|
1294
|
+
}, []);
|
|
1295
|
+
const features = useDefaultValue(props.features, () => ({
|
|
1296
|
+
selection: {
|
|
1297
|
+
enabled: false
|
|
1298
|
+
},
|
|
1299
|
+
dataEditable: false
|
|
1300
|
+
}));
|
|
1301
|
+
const model = useTableModel({
|
|
1302
|
+
rows,
|
|
1303
|
+
object: dynamicTable?.object,
|
|
1304
|
+
projection: dynamicTable?.projection,
|
|
1305
|
+
features,
|
|
1306
|
+
rowActions,
|
|
1307
|
+
onCellUpdate: handleCellUpdate,
|
|
1308
|
+
onRowOrderChange: handleRowOrderChange,
|
|
1309
|
+
onRowAction
|
|
1310
|
+
});
|
|
1311
|
+
const presentation = useMemo6(() => {
|
|
1312
|
+
if (model) {
|
|
1313
|
+
return new TablePresentation(registry, model);
|
|
1314
|
+
}
|
|
1315
|
+
}, [
|
|
1316
|
+
registry,
|
|
1317
|
+
model
|
|
1318
|
+
]);
|
|
1319
|
+
return /* @__PURE__ */ React10.createElement("div", {
|
|
1320
|
+
role: "none",
|
|
1321
|
+
className: mx2("dx-expander grid", classNames)
|
|
1322
|
+
}, /* @__PURE__ */ React10.createElement("div", {
|
|
1323
|
+
role: "none",
|
|
1324
|
+
className: "grid min-h-0 overflow-hidden"
|
|
1325
|
+
}, /* @__PURE__ */ React10.createElement(Table.Root, {
|
|
1326
|
+
ref: tableRef
|
|
1327
|
+
}, /* @__PURE__ */ React10.createElement(Table.Content, {
|
|
1328
|
+
model,
|
|
1329
|
+
presentation,
|
|
1330
|
+
ignoreAttention: true,
|
|
1331
|
+
onRowClick
|
|
1332
|
+
}))));
|
|
2725
1333
|
};
|
|
2726
1334
|
export {
|
|
2727
1335
|
BUTTON_IDENTIFIERS,
|
|
@@ -2733,18 +1341,21 @@ export {
|
|
|
2733
1341
|
Table,
|
|
2734
1342
|
TableModel,
|
|
2735
1343
|
TablePresentation,
|
|
2736
|
-
TableSchema,
|
|
2737
|
-
TableToolbar,
|
|
2738
|
-
TableType,
|
|
2739
1344
|
cellClassesForRowSelection,
|
|
1345
|
+
compareValues,
|
|
1346
|
+
createDirectChangeCallback,
|
|
1347
|
+
createEchoChangeCallback,
|
|
1348
|
+
extractOrder,
|
|
2740
1349
|
getBaseSchema,
|
|
2741
|
-
|
|
1350
|
+
getSortValue,
|
|
2742
1351
|
makeDynamicTable,
|
|
2743
1352
|
narrowSchema,
|
|
2744
1353
|
tableButtons,
|
|
2745
1354
|
tableControls,
|
|
2746
1355
|
touch,
|
|
2747
|
-
|
|
1356
|
+
useAddRow,
|
|
1357
|
+
useProjectionModel,
|
|
1358
|
+
useTableContext,
|
|
2748
1359
|
useTableModel
|
|
2749
1360
|
};
|
|
2750
1361
|
//# sourceMappingURL=index.mjs.map
|