@dxos/plugin-sheet 0.6.14-staging.9e90729 → 0.6.14-staging.c117501
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/{SheetContainer-JBB7W52Y.mjs → SheetContainer-P3NF5KEI.mjs} +60 -48
- package/dist/lib/browser/SheetContainer-P3NF5KEI.mjs.map +7 -0
- package/dist/lib/browser/{chunk-XXDHBYZQ.mjs → chunk-4LKIURJA.mjs} +337 -122
- package/dist/lib/browser/chunk-4LKIURJA.mjs.map +7 -0
- package/dist/lib/browser/{chunk-3QWIMZZJ.mjs → chunk-BVUN7SHF.mjs} +5 -3
- package/dist/lib/browser/chunk-BVUN7SHF.mjs.map +7 -0
- package/dist/lib/browser/{chunk-D3QTX46O.mjs → chunk-RABELMEQ.mjs} +3 -2
- package/dist/lib/browser/{chunk-D3QTX46O.mjs.map → chunk-RABELMEQ.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-2ZK3YMZG.mjs → chunk-VMSX6Z4X.mjs} +58 -20
- package/dist/lib/browser/chunk-VMSX6Z4X.mjs.map +7 -0
- package/dist/lib/browser/{compute-graph-ZQKB6QVP.mjs → compute-graph-GGWUX644.mjs} +4 -4
- package/dist/lib/browser/index.mjs +48 -21
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types.mjs +2 -2
- package/dist/lib/node/{SheetContainer-L37HUFCF.cjs → SheetContainer-MPFKXY26.cjs} +72 -63
- package/dist/lib/node/SheetContainer-MPFKXY26.cjs.map +7 -0
- package/dist/lib/node/{chunk-QIFIGEKV.cjs → chunk-2ZVZI2KJ.cjs} +6 -5
- package/dist/lib/node/{chunk-QIFIGEKV.cjs.map → chunk-2ZVZI2KJ.cjs.map} +3 -3
- package/dist/lib/node/{chunk-V7E5JZBD.cjs → chunk-AWKOWDMI.cjs} +9 -7
- package/dist/lib/node/chunk-AWKOWDMI.cjs.map +7 -0
- package/dist/lib/node/{chunk-QNFMTK3X.cjs → chunk-O7XR4R7Y.cjs} +69 -29
- package/dist/lib/node/chunk-O7XR4R7Y.cjs.map +7 -0
- package/dist/lib/node/{chunk-7AWAC3R3.cjs → chunk-OO24XJBV.cjs} +353 -139
- package/dist/lib/node/chunk-OO24XJBV.cjs.map +7 -0
- package/dist/lib/node/{compute-graph-RJB6OVW6.cjs → compute-graph-KGWA2QLE.cjs} +21 -21
- package/dist/lib/node/{compute-graph-RJB6OVW6.cjs.map → compute-graph-KGWA2QLE.cjs.map} +2 -2
- package/dist/lib/node/index.cjs +74 -46
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.cjs +3 -3
- package/dist/lib/node/meta.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types.cjs +7 -7
- package/dist/lib/node/types.cjs.map +1 -1
- package/dist/lib/node-esm/{SheetContainer-CLKFEM35.mjs → SheetContainer-22IOAW3B.mjs} +60 -48
- package/dist/lib/node-esm/SheetContainer-22IOAW3B.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-VCYJWE3O.mjs → chunk-BM2Q3FFC.mjs} +3 -2
- package/dist/lib/node-esm/{chunk-VCYJWE3O.mjs.map → chunk-BM2Q3FFC.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-3JYJEOCF.mjs → chunk-BW36PM2Y.mjs} +337 -122
- package/dist/lib/node-esm/chunk-BW36PM2Y.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-JBTORSST.mjs → chunk-CR4K75EL.mjs} +58 -20
- package/dist/lib/node-esm/chunk-CR4K75EL.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-SPQFLYC2.mjs → chunk-UIBWRHW7.mjs} +5 -3
- package/dist/lib/node-esm/chunk-UIBWRHW7.mjs.map +7 -0
- package/dist/lib/node-esm/{compute-graph-VKRG526N.mjs → compute-graph-2SCZT7N5.mjs} +4 -4
- package/dist/lib/node-esm/index.mjs +48 -21
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +1 -1
- package/dist/lib/node-esm/types.mjs +2 -2
- package/dist/types/src/SheetPlugin.d.ts.map +1 -1
- package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/util.d.ts +2 -2
- package/dist/types/src/components/GridSheet/util.d.ts.map +1 -1
- package/dist/types/src/components/RangeList/RangeList.d.ts +2 -4
- package/dist/types/src/components/RangeList/RangeList.d.ts.map +1 -1
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +6 -3
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -1
- package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +6 -3
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +4 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/compute-graph/compute-graph.d.ts +2 -2
- package/dist/types/src/compute-graph/compute-graph.d.ts.map +1 -1
- package/dist/types/src/compute-graph/functions/async-function.d.ts.map +1 -1
- package/dist/types/src/compute-graph/functions/edge-function.d.ts.map +1 -1
- package/dist/types/src/defs/sheet-range-types.d.ts +2 -2
- package/dist/types/src/defs/sheet-range-types.d.ts.map +1 -1
- package/dist/types/src/defs/util.d.ts +1 -1
- package/dist/types/src/defs/util.d.ts.map +1 -1
- package/dist/types/src/integrations/thread-ranges.d.ts +1 -2
- package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/model/sheet-model.d.ts +12 -5
- package/dist/types/src/model/sheet-model.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +12 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +33 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +37 -36
- package/src/SheetPlugin.tsx +27 -7
- package/src/components/FunctionEditor/FunctionEditor.tsx +1 -5
- package/src/components/GridSheet/GridSheet.tsx +107 -42
- package/src/components/GridSheet/util.ts +26 -16
- package/src/components/RangeList/RangeList.tsx +27 -12
- package/src/components/SheetContainer/SheetContainer.stories.tsx +4 -2
- package/src/components/SheetContainer/SheetContainer.tsx +19 -12
- package/src/components/Toolbar/Toolbar.tsx +72 -59
- package/src/compute-graph/compute-graph.ts +22 -7
- package/src/compute-graph/functions/async-function.ts +1 -0
- package/src/compute-graph/functions/edge-function.ts +5 -3
- package/src/defs/sheet-range-types.ts +8 -6
- package/src/defs/util.ts +1 -0
- package/src/integrations/thread-ranges.ts +3 -3
- package/src/meta.ts +1 -0
- package/src/model/sheet-model.test.ts +5 -3
- package/src/model/sheet-model.ts +93 -21
- package/src/translations.ts +12 -3
- package/src/types.ts +21 -1
- package/dist/lib/browser/SheetContainer-JBB7W52Y.mjs.map +0 -7
- package/dist/lib/browser/chunk-2ZK3YMZG.mjs.map +0 -7
- package/dist/lib/browser/chunk-3QWIMZZJ.mjs.map +0 -7
- package/dist/lib/browser/chunk-XXDHBYZQ.mjs.map +0 -7
- package/dist/lib/node/SheetContainer-L37HUFCF.cjs.map +0 -7
- package/dist/lib/node/chunk-7AWAC3R3.cjs.map +0 -7
- package/dist/lib/node/chunk-QNFMTK3X.cjs.map +0 -7
- package/dist/lib/node/chunk-V7E5JZBD.cjs.map +0 -7
- package/dist/lib/node-esm/SheetContainer-CLKFEM35.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-3JYJEOCF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JBTORSST.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SPQFLYC2.mjs.map +0 -7
- /package/dist/lib/browser/{compute-graph-ZQKB6QVP.mjs.map → compute-graph-GGWUX644.mjs.map} +0 -0
- /package/dist/lib/node-esm/{compute-graph-VKRG526N.mjs.map → compute-graph-2SCZT7N5.mjs.map} +0 -0
|
@@ -13,15 +13,18 @@ import React, {
|
|
|
13
13
|
useState,
|
|
14
14
|
} from 'react';
|
|
15
15
|
|
|
16
|
+
import { useIntentDispatcher } from '@dxos/app-framework';
|
|
16
17
|
import { DropdownMenu, Icon, useTranslation } from '@dxos/react-ui';
|
|
17
18
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
18
19
|
import {
|
|
19
20
|
closestCell,
|
|
21
|
+
defaultSizeRow,
|
|
20
22
|
editorKeys,
|
|
21
23
|
Grid,
|
|
22
24
|
GridCellEditor,
|
|
23
25
|
type DxGridElement,
|
|
24
|
-
type
|
|
26
|
+
type EditorKeyHandler,
|
|
27
|
+
type EditorBlurHandler,
|
|
25
28
|
type GridContentProps,
|
|
26
29
|
type DxGridPosition,
|
|
27
30
|
} from '@dxos/react-ui-grid';
|
|
@@ -31,6 +34,7 @@ import { DEFAULT_COLUMNS, DEFAULT_ROWS, rangeToA1Notation, type CellRange } from
|
|
|
31
34
|
import { rangeExtension, sheetExtension, type RangeController } from '../../extensions';
|
|
32
35
|
import { useSelectThreadOnCellFocus, useUpdateFocusedCellOnThreadSelection } from '../../integrations';
|
|
33
36
|
import { SHEET_PLUGIN } from '../../meta';
|
|
37
|
+
import { SheetAction } from '../../types';
|
|
34
38
|
import { useSheetContext } from '../SheetContext';
|
|
35
39
|
|
|
36
40
|
const inertPosition: DxGridPosition = { plane: 'grid', col: 0, row: 0 };
|
|
@@ -52,14 +56,20 @@ const frozen = {
|
|
|
52
56
|
frozenRowsStart: 1,
|
|
53
57
|
};
|
|
54
58
|
|
|
55
|
-
const sheetRowDefault = {
|
|
59
|
+
const sheetRowDefault = {
|
|
60
|
+
frozenRowsStart: { size: defaultSizeRow, readonly: true },
|
|
61
|
+
grid: { size: defaultSizeRow, resizeable: true },
|
|
62
|
+
};
|
|
56
63
|
const sheetColDefault = { frozenColsStart: { size: 48, readonly: true }, grid: { size: 180, resizeable: true } };
|
|
57
64
|
|
|
58
65
|
export const GridSheet = () => {
|
|
59
66
|
const { t } = useTranslation(SHEET_PLUGIN);
|
|
60
|
-
const { id, model, editing,
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
const { id, model, editing, setCursor, setRange, cursor, cursorFallbackRange, activeRefs } = useSheetContext();
|
|
68
|
+
// NOTE(thure): using `useState` instead of `useRef` works with refs provided by `@lit/react` and gives us
|
|
69
|
+
// a reliable dependency for `useEffect` whereas `useLayoutEffect` does not guarantee the element will be defined.
|
|
70
|
+
const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
|
|
71
|
+
const [extraplanarFocus, setExtraplanarFocus] = useState<DxGridPosition | null>(null);
|
|
72
|
+
const dispatch = useIntentDispatcher();
|
|
63
73
|
const rangeController = useRef<RangeController>();
|
|
64
74
|
const { hasAttention } = useAttention(id);
|
|
65
75
|
|
|
@@ -67,8 +77,15 @@ export const GridSheet = () => {
|
|
|
67
77
|
(event: FocusEvent) => {
|
|
68
78
|
if (!editing) {
|
|
69
79
|
const cell = closestCell(event.target);
|
|
70
|
-
if (cell
|
|
71
|
-
|
|
80
|
+
if (cell) {
|
|
81
|
+
if (cell.plane === 'grid') {
|
|
82
|
+
setCursor({ col: cell.col, row: cell.row });
|
|
83
|
+
setExtraplanarFocus(null);
|
|
84
|
+
} else {
|
|
85
|
+
setExtraplanarFocus(cell);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
setExtraplanarFocus(null);
|
|
72
89
|
}
|
|
73
90
|
}
|
|
74
91
|
},
|
|
@@ -76,29 +93,27 @@ export const GridSheet = () => {
|
|
|
76
93
|
);
|
|
77
94
|
|
|
78
95
|
// TODO(burdon): Validate formula before closing: hf.validateFormula();
|
|
79
|
-
const handleClose = useCallback<
|
|
80
|
-
(
|
|
81
|
-
if (
|
|
82
|
-
|
|
96
|
+
const handleClose = useCallback<EditorKeyHandler>(
|
|
97
|
+
(_value, event) => {
|
|
98
|
+
if (event) {
|
|
99
|
+
const { key, shift } = event;
|
|
100
|
+
const axis = ['Enter', 'ArrowUp', 'ArrowDown'].includes(key)
|
|
101
|
+
? 'row'
|
|
102
|
+
: ['Tab', 'ArrowLeft', 'ArrowRight'].includes(key)
|
|
103
|
+
? 'col'
|
|
104
|
+
: undefined;
|
|
105
|
+
const delta = key.startsWith('Arrow') ? (['ArrowUp', 'ArrowLeft'].includes(key) ? -1 : 1) : shift ? -1 : 1;
|
|
106
|
+
dxGrid?.refocus(axis, delta);
|
|
83
107
|
}
|
|
84
|
-
setEditing(null);
|
|
85
|
-
const axis = ['Enter', 'ArrowUp', 'ArrowDown'].includes(key)
|
|
86
|
-
? 'row'
|
|
87
|
-
: ['Tab', 'ArrowLeft', 'ArrowRight'].includes(key)
|
|
88
|
-
? 'col'
|
|
89
|
-
: undefined;
|
|
90
|
-
const delta = key.startsWith('Arrow') ? (['ArrowUp', 'ArrowLeft'].includes(key) ? -1 : 1) : shift ? -1 : 1;
|
|
91
|
-
dxGrid.current?.refocus(axis, delta);
|
|
92
108
|
},
|
|
93
|
-
[model, editing],
|
|
109
|
+
[model, editing, dxGrid],
|
|
94
110
|
);
|
|
95
111
|
|
|
96
|
-
const handleBlur = useCallback(
|
|
97
|
-
(value
|
|
112
|
+
const handleBlur = useCallback<EditorBlurHandler>(
|
|
113
|
+
(value) => {
|
|
98
114
|
if (value !== undefined) {
|
|
99
115
|
model.setValue(dxGridCellIndexToSheetCellAddress(editing!.index), value);
|
|
100
116
|
}
|
|
101
|
-
setEditing(null);
|
|
102
117
|
},
|
|
103
118
|
[model, editing],
|
|
104
119
|
);
|
|
@@ -143,6 +158,34 @@ export const GridSheet = () => {
|
|
|
143
158
|
[hasAttention],
|
|
144
159
|
);
|
|
145
160
|
|
|
161
|
+
const selectEntireAxis = useCallback(
|
|
162
|
+
(pos: DxGridPosition) => {
|
|
163
|
+
switch (pos.plane) {
|
|
164
|
+
case 'frozenRowsStart':
|
|
165
|
+
return dxGrid?.setSelection({
|
|
166
|
+
start: { col: pos.col, row: 0, plane: 'grid' },
|
|
167
|
+
end: { col: pos.col, row: model.sheet.rows.length - 1, plane: 'grid' },
|
|
168
|
+
});
|
|
169
|
+
case 'frozenColsStart':
|
|
170
|
+
return dxGrid?.setSelection({
|
|
171
|
+
start: { row: pos.row, col: 0, plane: 'grid' },
|
|
172
|
+
end: { row: pos.row, col: model.sheet.columns.length - 1, plane: 'grid' },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
[dxGrid, model.sheet],
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const handleClick = useCallback(
|
|
180
|
+
(event: MouseEvent) => {
|
|
181
|
+
const cell = closestCell(event.target);
|
|
182
|
+
if (cell) {
|
|
183
|
+
selectEntireAxis(cell);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
[selectEntireAxis],
|
|
187
|
+
);
|
|
188
|
+
|
|
146
189
|
const handleKeyDown = useCallback(
|
|
147
190
|
(event: KeyboardEvent) => {
|
|
148
191
|
switch (event.key) {
|
|
@@ -150,6 +193,16 @@ export const GridSheet = () => {
|
|
|
150
193
|
case 'Delete':
|
|
151
194
|
event.preventDefault();
|
|
152
195
|
return cursorFallbackRange && model.clear(cursorFallbackRange);
|
|
196
|
+
case 'Enter':
|
|
197
|
+
case 'Space':
|
|
198
|
+
if (dxGrid && extraplanarFocus) {
|
|
199
|
+
switch (extraplanarFocus.plane) {
|
|
200
|
+
case 'frozenRowsStart':
|
|
201
|
+
case 'frozenColsStart':
|
|
202
|
+
event.preventDefault();
|
|
203
|
+
return selectEntireAxis(extraplanarFocus);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
153
206
|
}
|
|
154
207
|
if (event.metaKey || event.ctrlKey) {
|
|
155
208
|
switch (event.key) {
|
|
@@ -175,7 +228,7 @@ export const GridSheet = () => {
|
|
|
175
228
|
}
|
|
176
229
|
}
|
|
177
230
|
},
|
|
178
|
-
[cursorFallbackRange, model, cursor],
|
|
231
|
+
[cursorFallbackRange, model, cursor, extraplanarFocus, selectEntireAxis],
|
|
179
232
|
);
|
|
180
233
|
|
|
181
234
|
const contextMenuAnchorRef = useRef<HTMLButtonElement | null>(null);
|
|
@@ -192,20 +245,31 @@ export const GridSheet = () => {
|
|
|
192
245
|
}, []);
|
|
193
246
|
|
|
194
247
|
const handleAxisMenuAction = useCallback(
|
|
195
|
-
(operation: '
|
|
248
|
+
(operation: 'insert-before' | 'insert-after' | 'drop') => {
|
|
196
249
|
switch (operation) {
|
|
197
|
-
case '
|
|
198
|
-
case '
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
250
|
+
case 'insert-before':
|
|
251
|
+
case 'insert-after':
|
|
252
|
+
return dispatch({
|
|
253
|
+
action: SheetAction.INSERT_AXIS,
|
|
254
|
+
data: {
|
|
255
|
+
model,
|
|
256
|
+
axis: contextMenuAxis,
|
|
257
|
+
index: contextMenuOpen![contextMenuAxis] + (operation === 'insert-before' ? 0 : 1),
|
|
258
|
+
} satisfies SheetAction.InsertAxis,
|
|
259
|
+
});
|
|
203
260
|
break;
|
|
204
|
-
case '
|
|
205
|
-
|
|
261
|
+
case 'drop':
|
|
262
|
+
return dispatch({
|
|
263
|
+
action: SheetAction.DROP_AXIS,
|
|
264
|
+
data: {
|
|
265
|
+
model,
|
|
266
|
+
axis: contextMenuAxis,
|
|
267
|
+
axisIndex: model.sheet[contextMenuAxis === 'row' ? 'rows' : 'columns'][contextMenuOpen![contextMenuAxis]],
|
|
268
|
+
} satisfies SheetAction.DropAxis,
|
|
269
|
+
});
|
|
206
270
|
}
|
|
207
271
|
},
|
|
208
|
-
[contextMenuAxis, contextMenuOpen, model],
|
|
272
|
+
[contextMenuAxis, contextMenuOpen, model, dispatch],
|
|
209
273
|
);
|
|
210
274
|
|
|
211
275
|
const { columns, rows } = useSheetModelDxGridProps(dxGrid, model);
|
|
@@ -217,9 +281,9 @@ export const GridSheet = () => {
|
|
|
217
281
|
rangeExtension({
|
|
218
282
|
onInit: (fn) => (rangeController.current = fn),
|
|
219
283
|
onStateChange: (state) => {
|
|
220
|
-
if (dxGrid
|
|
284
|
+
if (dxGrid) {
|
|
221
285
|
// This can’t dispatch a setState in this component, otherwise the cell editor remounts and loses focus.
|
|
222
|
-
dxGrid.
|
|
286
|
+
dxGrid.mode = typeof state.activeRange === 'undefined' ? 'edit' : 'edit-select';
|
|
223
287
|
}
|
|
224
288
|
},
|
|
225
289
|
}),
|
|
@@ -256,10 +320,11 @@ export const GridSheet = () => {
|
|
|
256
320
|
onWheelCapture={handleWheel}
|
|
257
321
|
onKeyDown={handleKeyDown}
|
|
258
322
|
onContextMenu={handleContextMenu}
|
|
259
|
-
|
|
260
|
-
|
|
323
|
+
onClick={handleClick}
|
|
324
|
+
overscroll='trap'
|
|
325
|
+
className='[--dx-grid-base:var(--surface-bg)] [&_.dx-grid]:border-bs [&_.dx-grid]:border-separator'
|
|
261
326
|
activeRefs={activeRefs}
|
|
262
|
-
ref={
|
|
327
|
+
ref={setDxGrid}
|
|
263
328
|
/>
|
|
264
329
|
<DropdownMenu.Root
|
|
265
330
|
modal={false}
|
|
@@ -269,21 +334,21 @@ export const GridSheet = () => {
|
|
|
269
334
|
<DropdownMenu.VirtualTrigger virtualRef={contextMenuAnchorRef} />
|
|
270
335
|
<DropdownMenu.Content side={contextMenuAxis === 'col' ? 'bottom' : 'right'} sideOffset={4} collisionPadding={8}>
|
|
271
336
|
<DropdownMenu.Viewport>
|
|
272
|
-
<DropdownMenu.Item onClick={() => handleAxisMenuAction('
|
|
337
|
+
<DropdownMenu.Item onClick={() => handleAxisMenuAction('insert-before')}>
|
|
273
338
|
<Icon
|
|
274
339
|
size={5}
|
|
275
340
|
icon={contextMenuAxis === 'col' ? 'ph--columns-plus-left--regular' : 'ph--rows-plus-top--regular'}
|
|
276
341
|
/>
|
|
277
342
|
<span>{t(`add ${contextMenuAxis} before label`)}</span>
|
|
278
343
|
</DropdownMenu.Item>
|
|
279
|
-
<DropdownMenu.Item onClick={() => handleAxisMenuAction('
|
|
344
|
+
<DropdownMenu.Item onClick={() => handleAxisMenuAction('insert-after')}>
|
|
280
345
|
<Icon
|
|
281
346
|
size={5}
|
|
282
347
|
icon={contextMenuAxis === 'col' ? 'ph--columns-plus-right--regular' : 'ph--rows-plus-bottom--regular'}
|
|
283
348
|
/>
|
|
284
349
|
<span>{t(`add ${contextMenuAxis} after label`)}</span>
|
|
285
350
|
</DropdownMenu.Item>
|
|
286
|
-
<DropdownMenu.Item
|
|
351
|
+
<DropdownMenu.Item onClick={() => handleAxisMenuAction('drop')}>
|
|
287
352
|
<Icon size={5} icon='ph--backspace--regular' />
|
|
288
353
|
<span>{t(`delete ${contextMenuAxis} label`)}</span>
|
|
289
354
|
</DropdownMenu.Item>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
6
|
|
|
7
7
|
import { createDocAccessor, fullyQualifiedId } from '@dxos/react-client/echo';
|
|
8
8
|
import { parseValue, cellClassesForFieldType } from '@dxos/react-ui-data';
|
|
@@ -67,16 +67,18 @@ const projectCellProps = (model: SheetModel, col: number, row: number): DxGridCe
|
|
|
67
67
|
})
|
|
68
68
|
.map((thread) => fullyQualifiedId(thread!))
|
|
69
69
|
.join(' ');
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
const description = model.getValueDescription(address);
|
|
72
|
+
const type = description?.type;
|
|
73
|
+
const format = description?.format;
|
|
71
74
|
const classNames = ranges?.map(cellClassNameForRange).reverse();
|
|
72
75
|
|
|
73
76
|
return {
|
|
74
|
-
value: parseValue(type, rawValue),
|
|
75
|
-
className: mx(cellClassesForFieldType(type), threadRefs && commentedClassName, classNames),
|
|
77
|
+
value: parseValue({ type, format, value: rawValue }),
|
|
78
|
+
className: mx(cellClassesForFieldType({ type, format }), threadRefs && commentedClassName, classNames),
|
|
76
79
|
dataRefs: threadRefs,
|
|
77
80
|
};
|
|
78
81
|
};
|
|
79
|
-
|
|
80
82
|
const gridCellGetter = (model: SheetModel) => {
|
|
81
83
|
// TODO(thure): Actually use the cache.
|
|
82
84
|
const cachedGridCells: DxGridPlaneCells = {};
|
|
@@ -94,11 +96,15 @@ const gridCellGetter = (model: SheetModel) => {
|
|
|
94
96
|
|
|
95
97
|
export const rowLabelCell = (row: number) => ({
|
|
96
98
|
value: rowToA1Notation(row),
|
|
97
|
-
className: 'text-end !pie-1',
|
|
99
|
+
className: 'text-end !pie-1 text-subdued',
|
|
98
100
|
resizeHandle: 'row',
|
|
99
101
|
});
|
|
100
102
|
|
|
101
|
-
export const colLabelCell = (col: number) => ({
|
|
103
|
+
export const colLabelCell = (col: number) => ({
|
|
104
|
+
value: colToA1Notation(col),
|
|
105
|
+
className: 'text-subdued',
|
|
106
|
+
resizeHandle: 'col',
|
|
107
|
+
});
|
|
102
108
|
|
|
103
109
|
const cellGetter = (model: SheetModel) => {
|
|
104
110
|
const getGridCells = gridCellGetter(model);
|
|
@@ -125,23 +131,27 @@ const cellGetter = (model: SheetModel) => {
|
|
|
125
131
|
};
|
|
126
132
|
|
|
127
133
|
export const useSheetModelDxGridProps = (
|
|
128
|
-
|
|
134
|
+
dxGrid: DxGridElement | null,
|
|
129
135
|
model: SheetModel,
|
|
130
136
|
): Pick<GridContentProps, 'columns' | 'rows'> => {
|
|
131
137
|
const [columns, setColumns] = useState<DxGridAxisMeta>(createDxGridColumns(model));
|
|
132
|
-
const [rows, setRows] = useState<DxGridAxisMeta>(
|
|
138
|
+
const [rows, setRows] = useState<DxGridAxisMeta>(createDxGridRows(model));
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
useEffect(() => {
|
|
135
141
|
const cellsAccessor = createDocAccessor(model.sheet, ['cells']);
|
|
136
|
-
if (
|
|
137
|
-
|
|
142
|
+
if (dxGrid) {
|
|
143
|
+
dxGrid.getCells = cellGetter(model);
|
|
138
144
|
}
|
|
139
145
|
const handleCellsUpdate = () => {
|
|
140
|
-
|
|
146
|
+
dxGrid?.requestUpdate('initialCells');
|
|
141
147
|
};
|
|
142
148
|
cellsAccessor.handle.addListener('change', handleCellsUpdate);
|
|
143
|
-
|
|
144
|
-
|
|
149
|
+
const unsubscribe = model.graph.update.on(handleCellsUpdate);
|
|
150
|
+
return () => {
|
|
151
|
+
cellsAccessor.handle.removeListener('change', handleCellsUpdate);
|
|
152
|
+
unsubscribe();
|
|
153
|
+
};
|
|
154
|
+
}, [model, dxGrid]);
|
|
145
155
|
|
|
146
156
|
useEffect(() => {
|
|
147
157
|
const columnMetaAccessor = createDocAccessor(model.sheet, ['columnMeta']);
|
|
@@ -158,7 +168,7 @@ export const useSheetModelDxGridProps = (
|
|
|
158
168
|
columnMetaAccessor.handle.removeListener('change', handleColumnMetaUpdate);
|
|
159
169
|
rowMetaAccessor.handle.removeListener('change', handleRowMetaUpdate);
|
|
160
170
|
};
|
|
161
|
-
}, [model]);
|
|
171
|
+
}, [model, dxGrid]);
|
|
162
172
|
|
|
163
173
|
return { columns, rows };
|
|
164
174
|
};
|
|
@@ -2,37 +2,52 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React from 'react';
|
|
5
|
+
import React, { useCallback } from 'react';
|
|
6
6
|
|
|
7
7
|
import { S } from '@dxos/echo-schema';
|
|
8
|
+
import { useTranslation } from '@dxos/react-ui';
|
|
8
9
|
import { List } from '@dxos/react-ui-list';
|
|
9
10
|
import { ghostHover } from '@dxos/react-ui-theme';
|
|
10
11
|
|
|
11
12
|
import { rangeFromIndex, rangeToA1Notation } from '../../defs';
|
|
13
|
+
import { SHEET_PLUGIN } from '../../meta';
|
|
12
14
|
import { Range, type SheetType } from '../../types';
|
|
13
15
|
|
|
14
16
|
export type RangeListProps = {
|
|
15
17
|
sheet: SheetType;
|
|
16
|
-
onSelect?: (range: Range) => void;
|
|
17
|
-
onDelete?: (range: Range) => void;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export const RangeList = ({ sheet
|
|
20
|
+
export const RangeList = ({ sheet }: RangeListProps) => {
|
|
21
|
+
const { t } = useTranslation(SHEET_PLUGIN);
|
|
22
|
+
// TODO(thure): Implement similar to comments, #8121
|
|
23
|
+
const handleSelectRange = (range: Range) => {};
|
|
24
|
+
const handleDeleteRange = useCallback(
|
|
25
|
+
(range: Range) => {
|
|
26
|
+
const index = sheet.ranges.findIndex((sheetRange) => sheetRange === range);
|
|
27
|
+
sheet.ranges.splice(index, 1);
|
|
28
|
+
},
|
|
29
|
+
[sheet],
|
|
30
|
+
);
|
|
21
31
|
return (
|
|
22
|
-
|
|
32
|
+
<>
|
|
33
|
+
<h2 className='p-2 text-sm font-semibold'>{t('range list heading')}</h2>
|
|
23
34
|
<List.Root<Range> items={sheet.ranges} isItem={S.is(Range)}>
|
|
24
|
-
{({ items }) =>
|
|
25
|
-
|
|
26
|
-
<List.Item key={i} item={
|
|
35
|
+
{({ items: ranges }) =>
|
|
36
|
+
ranges.map((range, i) => (
|
|
37
|
+
<List.Item key={i} item={range} classNames={['p-2', ghostHover]}>
|
|
27
38
|
<List.ItemDragHandle />
|
|
28
|
-
<List.ItemTitle onClick={() =>
|
|
29
|
-
{
|
|
39
|
+
<List.ItemTitle onClick={() => handleSelectRange(range)}>
|
|
40
|
+
{t('range title', {
|
|
41
|
+
position: rangeToA1Notation(rangeFromIndex(sheet, range.range)),
|
|
42
|
+
key: t(`range key ${range.key} label`),
|
|
43
|
+
value: t(`range value ${range.value} label`),
|
|
44
|
+
})}
|
|
30
45
|
</List.ItemTitle>
|
|
31
|
-
|
|
46
|
+
<List.ItemDeleteButton onClick={() => handleDeleteRange(range)} />
|
|
32
47
|
</List.Item>
|
|
33
48
|
))
|
|
34
49
|
}
|
|
35
50
|
</List.Root>
|
|
36
|
-
|
|
51
|
+
</>
|
|
37
52
|
);
|
|
38
53
|
};
|
|
@@ -11,6 +11,7 @@ import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
|
11
11
|
|
|
12
12
|
import { SheetContainer } from './SheetContainer';
|
|
13
13
|
import { createTestCells, useTestSheet, withComputeGraphDecorator } from '../../testing';
|
|
14
|
+
import translations from '../../translations';
|
|
14
15
|
import { SheetType } from '../../types';
|
|
15
16
|
import { useComputeGraph } from '../ComputeGraph';
|
|
16
17
|
|
|
@@ -18,11 +19,11 @@ export const Basic = () => {
|
|
|
18
19
|
const space = useSpace();
|
|
19
20
|
const graph = useComputeGraph(space);
|
|
20
21
|
const sheet = useTestSheet(space, graph, { cells: createTestCells() });
|
|
21
|
-
if (!sheet || !
|
|
22
|
+
if (!sheet || !space) {
|
|
22
23
|
return null;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
return <SheetContainer
|
|
26
|
+
return <SheetContainer space={space} sheet={sheet} role='article' />;
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
const meta: Meta = {
|
|
@@ -38,6 +39,7 @@ const meta: Meta = {
|
|
|
38
39
|
classNames: 'grid grid-cols-1 grid-rows-[min-content_minmax(0,1fr)_min-content]',
|
|
39
40
|
}),
|
|
40
41
|
],
|
|
42
|
+
parameters: { translations },
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
export default meta;
|
|
@@ -4,24 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
8
|
+
import { StackItem } from '@dxos/react-ui-stack';
|
|
9
|
+
|
|
10
|
+
import { type SheetType } from '../../types';
|
|
11
|
+
import { useComputeGraph } from '../ComputeGraph';
|
|
7
12
|
import { FunctionEditor } from '../FunctionEditor';
|
|
8
13
|
import { GridSheet } from '../GridSheet';
|
|
9
|
-
import { SheetProvider
|
|
14
|
+
import { SheetProvider } from '../SheetContext';
|
|
10
15
|
import { Toolbar } from '../Toolbar';
|
|
11
16
|
|
|
12
|
-
export const SheetContainer = ({
|
|
13
|
-
|
|
17
|
+
export const SheetContainer = ({ space, sheet, role }: { space: Space; sheet: SheetType; role?: string }) => {
|
|
18
|
+
const graph = useComputeGraph(space);
|
|
19
|
+
|
|
20
|
+
return graph ? (
|
|
14
21
|
<SheetProvider sheet={sheet} graph={graph}>
|
|
15
|
-
<
|
|
16
|
-
<Toolbar.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
<StackItem.Content toolbar statusbar classNames='border-bs border-separator'>
|
|
23
|
+
<Toolbar.Root role={role}>
|
|
24
|
+
<Toolbar.Styles />
|
|
25
|
+
<Toolbar.Alignment />
|
|
26
|
+
<Toolbar.Separator />
|
|
27
|
+
<Toolbar.Actions />
|
|
28
|
+
</Toolbar.Root>
|
|
22
29
|
<GridSheet />
|
|
23
30
|
<FunctionEditor />
|
|
24
|
-
</
|
|
31
|
+
</StackItem.Content>
|
|
25
32
|
</SheetProvider>
|
|
26
|
-
);
|
|
33
|
+
) : null;
|
|
27
34
|
};
|