@dxos/plugin-sheet 0.6.11 → 0.6.12-main.15a606f
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-V4GCCZTX.mjs +261 -0
- package/dist/lib/browser/SheetContainer-V4GCCZTX.mjs.map +7 -0
- package/dist/lib/browser/{chunk-D5AGLXJP.mjs → chunk-6ZMQVB4Z.mjs} +359 -671
- package/dist/lib/browser/chunk-6ZMQVB4Z.mjs.map +7 -0
- package/dist/lib/browser/{chunk-JRL5LGCE.mjs → chunk-QILRZNE5.mjs} +2 -5
- package/dist/lib/browser/chunk-QILRZNE5.mjs.map +7 -0
- package/dist/lib/browser/{chunk-FUAGSXA4.mjs → chunk-T3NJFTD4.mjs} +8 -15
- package/dist/lib/browser/chunk-T3NJFTD4.mjs.map +7 -0
- package/dist/lib/browser/{SheetContainer-U4H5D34A.mjs → chunk-U2JHW3L6.mjs} +1020 -240
- package/dist/lib/browser/chunk-U2JHW3L6.mjs.map +7 -0
- package/dist/lib/browser/graph-T27BOBOV.mjs +21 -0
- package/dist/lib/browser/graph-T27BOBOV.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +68 -56
- 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 +4 -6
- package/dist/lib/node/SheetContainer-3ZY7MPWJ.cjs +279 -0
- package/dist/lib/node/SheetContainer-3ZY7MPWJ.cjs.map +7 -0
- package/dist/lib/node/{chunk-BJ6ZD7MN.cjs → chunk-BNARJ5GM.cjs} +5 -18
- package/dist/lib/node/chunk-BNARJ5GM.cjs.map +7 -0
- package/dist/lib/node/{chunk-5KKJ4NPP.cjs → chunk-DD6FIXWC.cjs} +360 -667
- package/dist/lib/node/chunk-DD6FIXWC.cjs.map +7 -0
- package/dist/lib/node/{SheetContainer-AXQV3ZT5.cjs → chunk-OTTD7FBK.cjs} +1050 -279
- package/dist/lib/node/chunk-OTTD7FBK.cjs.map +7 -0
- package/dist/lib/node/{chunk-DSYKOI4E.cjs → chunk-Q3HBHPRL.cjs} +12 -20
- package/dist/lib/node/chunk-Q3HBHPRL.cjs.map +7 -0
- package/dist/lib/node/graph-SPKGX7W4.cjs +43 -0
- package/dist/lib/node/graph-SPKGX7W4.cjs.map +7 -0
- package/dist/lib/node/index.cjs +83 -64
- 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 +10 -12
- package/dist/lib/node/types.cjs.map +2 -2
- package/dist/lib/node-esm/SheetContainer-PXSJX6XK.mjs +262 -0
- package/dist/lib/node-esm/SheetContainer-PXSJX6XK.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-7HVSOTGA.mjs +2553 -0
- package/dist/lib/node-esm/chunk-7HVSOTGA.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-BMNA27EX.mjs +76 -0
- package/dist/lib/node-esm/chunk-BMNA27EX.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-D6KU5MI7.mjs +2925 -0
- package/dist/lib/node-esm/chunk-D6KU5MI7.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-IU2L277A.mjs +17 -0
- package/dist/lib/node-esm/chunk-IU2L277A.mjs.map +7 -0
- package/dist/lib/node-esm/graph-U67IO4UC.mjs +22 -0
- package/dist/lib/node-esm/graph-U67IO4UC.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +261 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/meta.mjs +10 -0
- package/dist/lib/node-esm/meta.mjs.map +7 -0
- package/dist/lib/node-esm/types.mjs +21 -0
- package/dist/lib/node-esm/types.mjs.map +7 -0
- package/dist/types/src/SheetPlugin.d.ts.map +1 -1
- package/dist/types/src/components/CellEditor/CellEditor.d.ts +23 -3
- package/dist/types/src/components/CellEditor/CellEditor.d.ts.map +1 -1
- package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts +2 -2
- package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/CellEditor/extension.d.ts +1 -1
- package/dist/types/src/components/CellEditor/extension.d.ts.map +1 -1
- package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts +11 -0
- package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts.map +1 -0
- package/dist/types/src/components/ComputeGraph/index.d.ts +1 -3
- package/dist/types/src/components/ComputeGraph/index.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.d.ts +10 -0
- package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -0
- package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +9 -0
- package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -0
- package/dist/types/src/components/GridSheet/util.d.ts +6 -0
- package/dist/types/src/components/GridSheet/util.d.ts.map +1 -0
- package/dist/types/src/components/Sheet/Sheet.d.ts +1 -1
- package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -1
- package/dist/types/src/components/Sheet/Sheet.stories.d.ts +5 -6
- package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +1 -1
- package/dist/types/src/components/Sheet/decorations.d.ts +24 -0
- package/dist/types/src/components/Sheet/decorations.d.ts.map +1 -0
- package/dist/types/src/components/Sheet/grid.d.ts +2 -2
- package/dist/types/src/components/Sheet/grid.d.ts.map +1 -1
- package/dist/types/src/components/Sheet/nav.d.ts +3 -3
- package/dist/types/src/components/Sheet/nav.d.ts.map +1 -1
- package/dist/types/src/components/Sheet/sheet-context.d.ts +6 -5
- package/dist/types/src/components/Sheet/sheet-context.d.ts.map +1 -1
- package/dist/types/src/components/Sheet/threads.d.ts +2 -0
- package/dist/types/src/components/Sheet/threads.d.ts.map +1 -0
- package/dist/types/src/components/SheetContainer.d.ts +2 -3
- package/dist/types/src/components/SheetContainer.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +19 -3
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +18 -13
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/defs/index.d.ts +3 -0
- package/dist/types/src/defs/index.d.ts.map +1 -0
- package/dist/types/src/{model → defs}/types.d.ts +8 -3
- package/dist/types/src/defs/types.d.ts.map +1 -0
- package/dist/types/src/defs/types.test.d.ts.map +1 -0
- package/dist/types/src/defs/util.d.ts +43 -0
- package/dist/types/src/defs/util.d.ts.map +1 -0
- package/dist/types/src/extensions/compute.d.ts +5 -0
- package/dist/types/src/extensions/compute.d.ts.map +1 -0
- package/dist/types/src/extensions/compute.stories.d.ts +26 -0
- package/dist/types/src/extensions/compute.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +2 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/{components/ComputeGraph → graph}/async-function.d.ts +1 -1
- package/dist/types/src/graph/async-function.d.ts.map +1 -0
- package/dist/types/src/graph/compute-graph.browser.test.d.ts +2 -0
- package/dist/types/src/graph/compute-graph.browser.test.d.ts.map +1 -0
- package/dist/types/src/graph/compute-graph.d.ts +81 -0
- package/dist/types/src/graph/compute-graph.d.ts.map +1 -0
- package/dist/types/src/graph/compute-graph.stories.d.ts +10 -0
- package/dist/types/src/graph/compute-graph.stories.d.ts.map +1 -0
- package/dist/types/src/graph/compute-node.d.ts +19 -0
- package/dist/types/src/graph/compute-node.d.ts.map +1 -0
- package/dist/types/src/{components/ComputeGraph/custom.d.ts → graph/custom-function.d.ts} +1 -1
- package/dist/types/src/graph/custom-function.d.ts.map +1 -0
- package/dist/types/src/graph/edge-function.d.ts.map +1 -0
- package/dist/types/src/{model/functions.d.ts → graph/function-defs.d.ts} +1 -1
- package/dist/types/src/graph/function-defs.d.ts.map +1 -0
- package/dist/types/src/graph/hyperformula.test.d.ts +2 -0
- package/dist/types/src/graph/hyperformula.test.d.ts.map +1 -0
- package/dist/types/src/graph/index.d.ts +4 -0
- package/dist/types/src/graph/index.d.ts.map +1 -0
- package/dist/types/src/graph/util.d.ts +2 -0
- package/dist/types/src/graph/util.d.ts.map +1 -0
- package/dist/types/src/hooks/hooks.stories.d.ts +11 -0
- package/dist/types/src/hooks/hooks.stories.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useComputeGraph.d.ts +7 -0
- package/dist/types/src/hooks/useComputeGraph.d.ts.map +1 -0
- package/dist/types/src/hooks/useFormattingModel.d.ts +3 -0
- package/dist/types/src/hooks/useFormattingModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useSheetModel.d.ts +8 -0
- package/dist/types/src/hooks/useSheetModel.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +1 -4
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/model/formatting-model.d.ts +16 -0
- package/dist/types/src/model/formatting-model.d.ts.map +1 -0
- package/dist/types/src/model/index.d.ts +2 -3
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/{model.d.ts → sheet-model.d.ts} +9 -64
- package/dist/types/src/model/sheet-model.d.ts.map +1 -0
- package/dist/types/src/sanity.test.d.ts +2 -0
- package/dist/types/src/sanity.test.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/testing.d.ts +9 -0
- package/dist/types/src/testing/testing.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +17 -12
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +83 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/vendor/hyperformula.mjs +37145 -0
- package/package.json +48 -41
- package/src/SheetPlugin.tsx +43 -70
- package/src/components/CellEditor/CellEditor.stories.tsx +4 -3
- package/src/components/CellEditor/CellEditor.tsx +59 -9
- package/src/components/CellEditor/extension.test.ts +4 -5
- package/src/components/CellEditor/extension.ts +1 -3
- package/src/components/ComputeGraph/ComputeGraphContextProvider.tsx +20 -0
- package/src/components/ComputeGraph/index.ts +1 -3
- package/src/components/GridSheet/GridSheet.stories.tsx +35 -0
- package/src/components/GridSheet/GridSheet.tsx +153 -0
- package/src/components/GridSheet/util.ts +89 -0
- package/src/components/Sheet/Sheet.stories.tsx +45 -82
- package/src/components/Sheet/Sheet.tsx +57 -18
- package/src/components/Sheet/decorations.ts +62 -0
- package/src/components/Sheet/grid.ts +3 -3
- package/src/components/Sheet/nav.ts +19 -19
- package/src/components/Sheet/sheet-context.tsx +16 -78
- package/src/components/Sheet/threads.tsx +205 -0
- package/src/components/SheetContainer.tsx +73 -19
- package/src/components/Toolbar/Toolbar.tsx +53 -12
- package/src/components/index.ts +1 -0
- package/src/defs/index.ts +6 -0
- package/src/{model → defs}/types.test.ts +8 -9
- package/src/{model → defs}/types.ts +23 -14
- package/src/defs/util.ts +135 -0
- package/src/extensions/compute.stories.tsx +151 -0
- package/src/extensions/compute.ts +98 -0
- package/src/extensions/index.ts +5 -0
- package/src/{components/ComputeGraph → graph}/async-function.ts +3 -1
- package/src/graph/compute-graph.browser.test.ts +104 -0
- package/src/graph/compute-graph.stories.tsx +92 -0
- package/src/graph/compute-graph.ts +290 -0
- package/src/graph/compute-node.ts +51 -0
- package/src/{components/ComputeGraph/custom.ts → graph/custom-function.ts} +2 -6
- package/src/{components/ComputeGraph → graph}/edge-function.ts +2 -1
- package/src/graph/hyperformula.test.ts +15 -0
- package/src/graph/index.ts +7 -0
- package/src/graph/util.ts +8 -0
- package/src/hooks/hooks.stories.tsx +50 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useComputeGraph.ts +20 -0
- package/src/hooks/useFormattingModel.ts +11 -0
- package/src/hooks/useSheetModel.ts +43 -0
- package/src/meta.tsx +1 -5
- package/src/{components/Sheet/formatting.ts → model/formatting-model.ts} +20 -13
- package/src/model/index.ts +2 -3
- package/src/model/sheet-model.ts +399 -0
- package/src/sanity.test.ts +40 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/testing.tsx +66 -0
- package/src/translations.ts +6 -1
- package/src/types.ts +30 -5
- package/dist/lib/browser/SheetContainer-U4H5D34A.mjs.map +0 -7
- package/dist/lib/browser/chunk-APHOLYUB.mjs +0 -175
- package/dist/lib/browser/chunk-APHOLYUB.mjs.map +0 -7
- package/dist/lib/browser/chunk-D5AGLXJP.mjs.map +0 -7
- package/dist/lib/browser/chunk-FUAGSXA4.mjs.map +0 -7
- package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +0 -7
- package/dist/lib/browser/chunk-NU4PBN33.mjs +0 -8
- package/dist/lib/browser/chunk-NU4PBN33.mjs.map +0 -7
- package/dist/lib/browser/testing.mjs +0 -92
- package/dist/lib/browser/testing.mjs.map +0 -7
- package/dist/lib/node/SheetContainer-AXQV3ZT5.cjs.map +0 -7
- package/dist/lib/node/chunk-5KKJ4NPP.cjs.map +0 -7
- package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +0 -7
- package/dist/lib/node/chunk-CN3RPESU.cjs +0 -202
- package/dist/lib/node/chunk-CN3RPESU.cjs.map +0 -7
- package/dist/lib/node/chunk-DSYKOI4E.cjs.map +0 -7
- package/dist/lib/node/chunk-PYXHNAAK.cjs +0 -40
- package/dist/lib/node/chunk-PYXHNAAK.cjs.map +0 -7
- package/dist/lib/node/testing.cjs +0 -111
- package/dist/lib/node/testing.cjs.map +0 -7
- package/dist/types/src/components/ComputeGraph/async-function.d.ts.map +0 -1
- package/dist/types/src/components/ComputeGraph/custom.d.ts.map +0 -1
- package/dist/types/src/components/ComputeGraph/edge-function.d.ts.map +0 -1
- package/dist/types/src/components/ComputeGraph/graph-context.d.ts +0 -12
- package/dist/types/src/components/ComputeGraph/graph-context.d.ts.map +0 -1
- package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts +0 -2
- package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts.map +0 -1
- package/dist/types/src/components/ComputeGraph/graph.d.ts +0 -26
- package/dist/types/src/components/ComputeGraph/graph.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/formatting.d.ts +0 -14
- package/dist/types/src/components/Sheet/formatting.d.ts.map +0 -1
- package/dist/types/src/model/functions.d.ts.map +0 -1
- package/dist/types/src/model/model.browser.test.d.ts +0 -2
- package/dist/types/src/model/model.browser.test.d.ts.map +0 -1
- package/dist/types/src/model/model.d.ts.map +0 -1
- package/dist/types/src/model/types.d.ts.map +0 -1
- package/dist/types/src/model/types.test.d.ts.map +0 -1
- package/dist/types/src/model/util.d.ts +0 -15
- package/dist/types/src/model/util.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -9
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/components/ComputeGraph/graph-context.tsx +0 -50
- package/src/components/ComputeGraph/graph.browser.test.ts +0 -50
- package/src/components/ComputeGraph/graph.ts +0 -62
- package/src/model/model.browser.test.ts +0 -100
- package/src/model/model.ts +0 -550
- package/src/model/util.ts +0 -36
- package/src/testing.ts +0 -50
- /package/dist/types/src/{model → defs}/types.test.d.ts +0 -0
- /package/dist/types/src/{components/ComputeGraph → graph}/edge-function.d.ts +0 -0
- /package/src/{model/functions.ts → graph/function-defs.ts} +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback, useMemo, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type Space } from '@dxos/client/echo';
|
|
8
|
+
import {
|
|
9
|
+
type DxGridElement,
|
|
10
|
+
Grid,
|
|
11
|
+
type GridContentProps,
|
|
12
|
+
type GridScopedProps,
|
|
13
|
+
useGridContext,
|
|
14
|
+
} from '@dxos/react-ui-grid';
|
|
15
|
+
|
|
16
|
+
import { dxGridCellIndexToSheetCellAddress, useSheetModelDxGridProps } from './util';
|
|
17
|
+
import { rangeToA1Notation, type CellRange } from '../../defs';
|
|
18
|
+
import { useFormattingModel, useSheetModel, type UseSheetModelOptions } from '../../hooks';
|
|
19
|
+
import { type SheetModel, type FormattingModel } from '../../model';
|
|
20
|
+
import { type SheetType } from '../../types';
|
|
21
|
+
import {
|
|
22
|
+
CellEditor,
|
|
23
|
+
type CellEditorProps,
|
|
24
|
+
type CellRangeNotifier,
|
|
25
|
+
editorKeys,
|
|
26
|
+
type EditorKeysProps,
|
|
27
|
+
rangeExtension,
|
|
28
|
+
sheetExtension,
|
|
29
|
+
} from '../CellEditor';
|
|
30
|
+
|
|
31
|
+
const GridSheetCellEditor = ({
|
|
32
|
+
model,
|
|
33
|
+
extension,
|
|
34
|
+
__gridScope,
|
|
35
|
+
}: GridScopedProps<Pick<CellEditorProps, 'extension'> & { model: SheetModel }>) => {
|
|
36
|
+
const { id, editing, setEditing, editBox } = useGridContext('GridSheetCellEditor', __gridScope);
|
|
37
|
+
const cell = dxGridCellIndexToSheetCellAddress(editing);
|
|
38
|
+
|
|
39
|
+
return editing ? (
|
|
40
|
+
<CellEditor
|
|
41
|
+
variant='grid'
|
|
42
|
+
value={editing.initialContent ?? (cell ? model.getCellText(cell) : undefined)}
|
|
43
|
+
autoFocus
|
|
44
|
+
box={editBox}
|
|
45
|
+
onBlur={() => setEditing(null)}
|
|
46
|
+
extension={extension}
|
|
47
|
+
gridId={id}
|
|
48
|
+
/>
|
|
49
|
+
) : null;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const sheetRowDefault = { size: 32, resizeable: true };
|
|
53
|
+
const sheetColDefault = { size: 180, resizeable: true };
|
|
54
|
+
|
|
55
|
+
const GridSheetImpl = ({
|
|
56
|
+
model,
|
|
57
|
+
formatting,
|
|
58
|
+
__gridScope,
|
|
59
|
+
}: GridScopedProps<{ model: SheetModel; formatting: FormattingModel }>) => {
|
|
60
|
+
const { editing, setEditing } = useGridContext('GridSheetCellEditor', __gridScope);
|
|
61
|
+
const dxGrid = useRef<DxGridElement | null>(null);
|
|
62
|
+
const rangeNotifier = useRef<CellRangeNotifier>();
|
|
63
|
+
|
|
64
|
+
// TODO(burdon): Validate formula before closing: hf.validateFormula();
|
|
65
|
+
const handleClose = useCallback<NonNullable<EditorKeysProps['onClose']> | NonNullable<EditorKeysProps['onNav']>>(
|
|
66
|
+
(value, { key, shift }) => {
|
|
67
|
+
if (value !== undefined) {
|
|
68
|
+
model.setValue(dxGridCellIndexToSheetCellAddress(editing)!, value);
|
|
69
|
+
}
|
|
70
|
+
setEditing(null);
|
|
71
|
+
const axis = ['Enter', 'ArrowUp', 'ArrowDown'].includes(key)
|
|
72
|
+
? 'row'
|
|
73
|
+
: ['Tab', 'ArrowLeft', 'ArrowRight'].includes(key)
|
|
74
|
+
? 'col'
|
|
75
|
+
: undefined;
|
|
76
|
+
const delta = key.startsWith('Arrow') ? (['ArrowUp', 'ArrowLeft'].includes(key) ? -1 : 1) : shift ? -1 : 1;
|
|
77
|
+
dxGrid.current?.refocus(axis, delta);
|
|
78
|
+
},
|
|
79
|
+
[model, editing, setEditing],
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const handleAxisResize = useCallback<NonNullable<GridContentProps['onAxisResize']>>(
|
|
83
|
+
({ axis, size, index: numericIndex }) => {
|
|
84
|
+
if (axis === 'row') {
|
|
85
|
+
const rowId = model.sheet.rows[parseInt(numericIndex)];
|
|
86
|
+
model.sheet.rowMeta[rowId] ??= {};
|
|
87
|
+
model.sheet.rowMeta[rowId].size = size;
|
|
88
|
+
} else {
|
|
89
|
+
const columnId = model.sheet.columns[parseInt(numericIndex)];
|
|
90
|
+
model.sheet.columnMeta[columnId] ??= {};
|
|
91
|
+
model.sheet.columnMeta[columnId].size = size;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
[model],
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const handleSelect = useCallback<NonNullable<GridContentProps['onSelect']>>(
|
|
98
|
+
({ minCol, maxCol, minRow, maxRow }) => {
|
|
99
|
+
if (editing) {
|
|
100
|
+
const range: CellRange = { from: { col: minCol, row: minRow } };
|
|
101
|
+
if (minCol !== maxCol || minRow !== maxRow) {
|
|
102
|
+
range.to = { col: maxCol, row: maxRow };
|
|
103
|
+
}
|
|
104
|
+
// Update range selection in formula.
|
|
105
|
+
rangeNotifier.current?.(rangeToA1Notation(range));
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[editing],
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const { cells, columns, rows } = useSheetModelDxGridProps(model, formatting);
|
|
112
|
+
|
|
113
|
+
const extension = useMemo(
|
|
114
|
+
() => [
|
|
115
|
+
editorKeys({ onClose: handleClose, ...(editing?.initialContent && { onNav: handleClose }) }),
|
|
116
|
+
sheetExtension({ functions: model.graph.getFunctions() }),
|
|
117
|
+
rangeExtension((fn) => (rangeNotifier.current = fn)),
|
|
118
|
+
],
|
|
119
|
+
[model, handleClose, editing],
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<>
|
|
124
|
+
<GridSheetCellEditor model={model} extension={extension} />
|
|
125
|
+
<Grid.Content
|
|
126
|
+
cells={cells}
|
|
127
|
+
columns={columns}
|
|
128
|
+
rows={rows}
|
|
129
|
+
onAxisResize={handleAxisResize}
|
|
130
|
+
onSelect={handleSelect}
|
|
131
|
+
rowDefault={sheetRowDefault}
|
|
132
|
+
columnDefault={sheetColDefault}
|
|
133
|
+
ref={dxGrid}
|
|
134
|
+
/>
|
|
135
|
+
</>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type GridSheetProps = { space?: Space; sheet?: SheetType } & UseSheetModelOptions;
|
|
140
|
+
|
|
141
|
+
export const GridSheet = ({ space, sheet, ...options }: GridSheetProps) => {
|
|
142
|
+
const model = useSheetModel(space, sheet, options);
|
|
143
|
+
const formatting = useFormattingModel(model);
|
|
144
|
+
if (!model || !formatting) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<Grid.Root id={model.id}>
|
|
150
|
+
<GridSheetImpl model={model} formatting={formatting} />
|
|
151
|
+
</Grid.Root>
|
|
152
|
+
);
|
|
153
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { createDocAccessor } from '@dxos/react-client/echo';
|
|
8
|
+
import { type GridEditing, type GridContentProps } from '@dxos/react-ui-grid';
|
|
9
|
+
import { mx } from '@dxos/react-ui-theme';
|
|
10
|
+
|
|
11
|
+
import { addressFromIndex, type CellAddress } from '../../defs';
|
|
12
|
+
import { type SheetModel, type FormattingModel } from '../../model';
|
|
13
|
+
|
|
14
|
+
export const dxGridCellIndexToSheetCellAddress = (gridEditing: GridEditing): CellAddress | null => {
|
|
15
|
+
if (!gridEditing) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const [colStr, rowStr] = gridEditing.index.split(',');
|
|
19
|
+
return {
|
|
20
|
+
col: parseInt(colStr),
|
|
21
|
+
row: parseInt(rowStr),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const createDxGridCells = (model: SheetModel, formatting: FormattingModel) => {
|
|
26
|
+
return Object.keys(model.sheet.cells).reduce((acc: NonNullable<GridContentProps['cells']>, sheetCellIndex) => {
|
|
27
|
+
const address = addressFromIndex(model.sheet, sheetCellIndex);
|
|
28
|
+
const cell = formatting.getFormatting(address);
|
|
29
|
+
if (cell.value) {
|
|
30
|
+
acc[`${address.col},${address.row}`] = { value: cell.value, className: mx(cell.classNames) };
|
|
31
|
+
}
|
|
32
|
+
return acc;
|
|
33
|
+
}, {});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const createDxGridColumns = (model: SheetModel): GridContentProps['columns'] => {
|
|
37
|
+
return model.sheet.columns.reduce((acc: NonNullable<GridContentProps['columns']>, columnId, numericIndex) => {
|
|
38
|
+
if (model.sheet.columnMeta[columnId] && model.sheet.columnMeta[columnId].size) {
|
|
39
|
+
acc[numericIndex] = { size: model.sheet.columnMeta[columnId].size, resizeable: true };
|
|
40
|
+
}
|
|
41
|
+
return acc;
|
|
42
|
+
}, {});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const createDxGridRows = (model: SheetModel): GridContentProps['rows'] => {
|
|
46
|
+
return model.sheet.rows.reduce((acc: NonNullable<GridContentProps['rows']>, rowId, numericIndex) => {
|
|
47
|
+
if (model.sheet.rowMeta[rowId] && model.sheet.rowMeta[rowId].size) {
|
|
48
|
+
acc[numericIndex] = { size: model.sheet.rowMeta[rowId].size, resizeable: true };
|
|
49
|
+
}
|
|
50
|
+
return acc;
|
|
51
|
+
}, {});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const useSheetModelDxGridProps = (
|
|
55
|
+
model: SheetModel,
|
|
56
|
+
formatting: FormattingModel,
|
|
57
|
+
): Pick<GridContentProps, 'cells' | 'columns' | 'rows'> => {
|
|
58
|
+
const [dxGridCells, setDxGridCells] = useState<GridContentProps['cells']>(createDxGridCells(model, formatting));
|
|
59
|
+
const [dxGridColumns, setDxGridColumns] = useState<GridContentProps['columns']>(createDxGridColumns(model));
|
|
60
|
+
const [dxGridRows, setDxGridRows] = useState<GridContentProps['rows']>(createDxGridColumns(model));
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const cellsAccessor = createDocAccessor(model.sheet, ['cells']);
|
|
64
|
+
const handleCellsUpdate = () => {
|
|
65
|
+
setDxGridCells(createDxGridCells(model, formatting));
|
|
66
|
+
};
|
|
67
|
+
cellsAccessor.handle.addListener('change', handleCellsUpdate);
|
|
68
|
+
return () => cellsAccessor.handle.removeListener('change', handleCellsUpdate);
|
|
69
|
+
}, [model, formatting]);
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const columnMetaAccessor = createDocAccessor(model.sheet, ['columnMeta']);
|
|
73
|
+
const rowMetaAccessor = createDocAccessor(model.sheet, ['rowMeta']);
|
|
74
|
+
const handleColumnMetaUpdate = () => {
|
|
75
|
+
setDxGridColumns(createDxGridColumns(model));
|
|
76
|
+
};
|
|
77
|
+
const handleRowMetaUpdate = () => {
|
|
78
|
+
setDxGridRows(createDxGridRows(model));
|
|
79
|
+
};
|
|
80
|
+
columnMetaAccessor.handle.addListener('change', handleColumnMetaUpdate);
|
|
81
|
+
rowMetaAccessor.handle.addListener('change', handleRowMetaUpdate);
|
|
82
|
+
return () => {
|
|
83
|
+
columnMetaAccessor.handle.removeListener('change', handleColumnMetaUpdate);
|
|
84
|
+
rowMetaAccessor.handle.removeListener('change', handleRowMetaUpdate);
|
|
85
|
+
};
|
|
86
|
+
}, [model]);
|
|
87
|
+
|
|
88
|
+
return { cells: dxGridCells, columns: dxGridColumns, rows: dxGridRows };
|
|
89
|
+
};
|
|
@@ -4,31 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import React, { useContext, useEffect, useState } from 'react';
|
|
7
|
+
import React, { useState } from 'react';
|
|
9
8
|
|
|
10
|
-
import { Client } from '@dxos/client';
|
|
11
|
-
import { type EchoReactiveObject } from '@dxos/echo-schema';
|
|
12
9
|
import { log } from '@dxos/log';
|
|
13
|
-
import {
|
|
10
|
+
import { type Space, useSpace } from '@dxos/react-client/echo';
|
|
11
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
14
12
|
import { Button } from '@dxos/react-ui';
|
|
15
13
|
import { mx } from '@dxos/react-ui-theme';
|
|
16
|
-
import {
|
|
14
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
17
15
|
|
|
18
16
|
import { Sheet } from './Sheet';
|
|
19
17
|
import { type SizeMap } from './grid';
|
|
20
18
|
import { useSheetContext } from './sheet-context';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
import { ComputeGraphContext, ComputeGraphContextProvider, useComputeGraph } from '../ComputeGraph/graph-context';
|
|
19
|
+
import { addressToIndex, rangeToIndex } from '../../defs';
|
|
20
|
+
import { useComputeGraph } from '../../hooks';
|
|
21
|
+
import { useTestSheet, withGraphDecorator } from '../../testing';
|
|
22
|
+
import { SheetType, ValueTypeEnum } from '../../types';
|
|
26
23
|
import { Toolbar, type ToolbarActionHandler } from '../Toolbar';
|
|
27
24
|
|
|
28
25
|
// TODO(burdon): Allow toolbar to access sheet context; provide state for current cursor/range.
|
|
29
26
|
const SheetWithToolbar = ({ debug, space }: { debug?: boolean; space: Space }) => {
|
|
30
27
|
const { model, cursor, range } = useSheetContext();
|
|
31
28
|
|
|
29
|
+
const graph = useComputeGraph(space);
|
|
30
|
+
const handleRefresh = () => {
|
|
31
|
+
graph?.refresh();
|
|
32
|
+
};
|
|
33
|
+
|
|
32
34
|
// TODO(burdon): Factor out.
|
|
33
35
|
const handleAction: ToolbarActionHandler = ({ type }) => {
|
|
34
36
|
log.info('action', { type, cursor, range });
|
|
@@ -36,7 +38,7 @@ const SheetWithToolbar = ({ debug, space }: { debug?: boolean; space: Space }) =
|
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
const idx = range ? model.
|
|
41
|
+
const idx = range ? rangeToIndex(model.sheet, range) : addressToIndex(model.sheet, cursor);
|
|
40
42
|
model.sheet.formatting[idx] ??= {};
|
|
41
43
|
const format = model.sheet.formatting[idx];
|
|
42
44
|
|
|
@@ -75,14 +77,12 @@ const SheetWithToolbar = ({ debug, space }: { debug?: boolean; space: Space }) =
|
|
|
75
77
|
format.precision = 2;
|
|
76
78
|
break;
|
|
77
79
|
}
|
|
80
|
+
case 'comment': {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
78
83
|
}
|
|
79
84
|
};
|
|
80
85
|
|
|
81
|
-
const graph = useComputeGraph(space);
|
|
82
|
-
const handleRefresh = () => {
|
|
83
|
-
graph.refresh();
|
|
84
|
-
};
|
|
85
|
-
|
|
86
86
|
return (
|
|
87
87
|
<div className='flex flex-col overflow-hidden'>
|
|
88
88
|
<Toolbar.Root onAction={handleAction}>
|
|
@@ -99,56 +99,43 @@ const SheetWithToolbar = ({ debug, space }: { debug?: boolean; space: Space }) =
|
|
|
99
99
|
);
|
|
100
100
|
};
|
|
101
101
|
|
|
102
|
-
const withGraphDecorator: Decorator = (Story) => {
|
|
103
|
-
const [graphs, setGraphs] = useState<Record<string, ComputeGraph>>({});
|
|
104
|
-
|
|
105
|
-
const setGraph = (key: string, graph: ComputeGraph) => {
|
|
106
|
-
if (!graph.hf.doesSheetExist(testSheetName)) {
|
|
107
|
-
const sheetName = graph.hf.addSheet(testSheetName);
|
|
108
|
-
const sheet = graph.hf.getSheetId(sheetName)!;
|
|
109
|
-
graph.hf.setCellContents({ sheet, col: 0, row: 0 }, Math.random());
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
setGraphs((graphs) => ({ ...graphs, [key]: graph }));
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return (
|
|
116
|
-
<ComputeGraphContextProvider graphs={graphs} setGraph={setGraph}>
|
|
117
|
-
<Story />
|
|
118
|
-
</ComputeGraphContextProvider>
|
|
119
|
-
);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
102
|
export default {
|
|
123
103
|
title: 'plugin-sheet/Sheet',
|
|
124
104
|
component: Sheet,
|
|
125
|
-
decorators: [
|
|
105
|
+
decorators: [
|
|
106
|
+
withClientProvider({ types: [SheetType], createIdentity: true }),
|
|
107
|
+
withGraphDecorator,
|
|
108
|
+
withTheme,
|
|
109
|
+
withLayout({ fullscreen: true, tooltips: true, classNames: 'inset-4' }),
|
|
110
|
+
],
|
|
126
111
|
};
|
|
127
112
|
|
|
128
113
|
export const Default = () => {
|
|
129
114
|
const [debug, setDebug] = useState(false);
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
115
|
+
const space = useSpace();
|
|
116
|
+
const graph = useComputeGraph(space);
|
|
117
|
+
const sheet = useTestSheet(space, graph);
|
|
118
|
+
if (!space || !sheet) {
|
|
133
119
|
return null;
|
|
134
120
|
}
|
|
135
121
|
|
|
136
122
|
return (
|
|
137
|
-
<Sheet.Root
|
|
123
|
+
<Sheet.Root space={space} sheet={sheet} onInfo={() => setDebug((debug) => !debug)}>
|
|
138
124
|
<SheetWithToolbar debug={debug} space={space} />
|
|
139
125
|
</Sheet.Root>
|
|
140
126
|
);
|
|
141
127
|
};
|
|
142
128
|
|
|
143
129
|
export const Debug = () => {
|
|
144
|
-
const
|
|
145
|
-
const
|
|
130
|
+
const space = useSpace();
|
|
131
|
+
const graph = useComputeGraph(space);
|
|
132
|
+
const sheet = useTestSheet(space, graph);
|
|
146
133
|
if (!sheet || !space) {
|
|
147
134
|
return null;
|
|
148
135
|
}
|
|
149
136
|
|
|
150
137
|
return (
|
|
151
|
-
<Sheet.Root
|
|
138
|
+
<Sheet.Root space={space} sheet={sheet}>
|
|
152
139
|
<Sheet.Main />
|
|
153
140
|
<Sheet.Debug />
|
|
154
141
|
</Sheet.Root>
|
|
@@ -157,14 +144,15 @@ export const Debug = () => {
|
|
|
157
144
|
|
|
158
145
|
export const Rows = () => {
|
|
159
146
|
const [rowSizes, setRowSizes] = useState<SizeMap>({});
|
|
160
|
-
const
|
|
161
|
-
const
|
|
147
|
+
const space = useSpace();
|
|
148
|
+
const graph = useComputeGraph(space);
|
|
149
|
+
const sheet = useTestSheet(space, graph);
|
|
162
150
|
if (!sheet || !space) {
|
|
163
151
|
return null;
|
|
164
152
|
}
|
|
165
153
|
|
|
166
154
|
return (
|
|
167
|
-
<Sheet.Root
|
|
155
|
+
<Sheet.Root space={space} sheet={sheet}>
|
|
168
156
|
<Sheet.Rows
|
|
169
157
|
rows={sheet.rows}
|
|
170
158
|
sizes={rowSizes}
|
|
@@ -176,14 +164,15 @@ export const Rows = () => {
|
|
|
176
164
|
|
|
177
165
|
export const Columns = () => {
|
|
178
166
|
const [columnSizes, setColumnSizes] = useState<SizeMap>({});
|
|
179
|
-
const
|
|
180
|
-
const
|
|
167
|
+
const space = useSpace();
|
|
168
|
+
const graph = useComputeGraph(space);
|
|
169
|
+
const sheet = useTestSheet(space, graph);
|
|
181
170
|
if (!sheet || !space) {
|
|
182
171
|
return null;
|
|
183
172
|
}
|
|
184
173
|
|
|
185
174
|
return (
|
|
186
|
-
<Sheet.Root
|
|
175
|
+
<Sheet.Root space={space} sheet={sheet}>
|
|
187
176
|
<Sheet.Columns
|
|
188
177
|
columns={sheet.columns}
|
|
189
178
|
sizes={columnSizes}
|
|
@@ -194,18 +183,19 @@ export const Columns = () => {
|
|
|
194
183
|
};
|
|
195
184
|
|
|
196
185
|
export const Main = () => {
|
|
197
|
-
const
|
|
198
|
-
const
|
|
186
|
+
const space = useSpace();
|
|
187
|
+
const graph = useComputeGraph(space);
|
|
188
|
+
const sheet = useTestSheet(space, graph);
|
|
199
189
|
if (!sheet || !space) {
|
|
200
190
|
return null;
|
|
201
191
|
}
|
|
202
192
|
|
|
203
193
|
return (
|
|
204
|
-
<Sheet.Root
|
|
194
|
+
<Sheet.Root space={space} sheet={sheet}>
|
|
205
195
|
<Sheet.Grid
|
|
206
196
|
size={{
|
|
207
197
|
numRows: 50,
|
|
208
|
-
|
|
198
|
+
numCols: 26,
|
|
209
199
|
}}
|
|
210
200
|
rows={sheet.rows}
|
|
211
201
|
columns={sheet.columns}
|
|
@@ -258,30 +248,3 @@ export const GridLayout = () => {
|
|
|
258
248
|
const Cell = ({ className, label }: { className?: string; label: string }) => (
|
|
259
249
|
<div className={mx('flex items-center justify-center border', className)}>{label}</div>
|
|
260
250
|
);
|
|
261
|
-
|
|
262
|
-
const useTestSheet = () => {
|
|
263
|
-
const { graphs, setGraph } = useContext(ComputeGraphContext);
|
|
264
|
-
const [sheet, setSheet] = useState<EchoReactiveObject<SheetType>>();
|
|
265
|
-
useEffect(() => {
|
|
266
|
-
const t = setTimeout(async () => {
|
|
267
|
-
const client = new Client();
|
|
268
|
-
await client.initialize();
|
|
269
|
-
await client.halo.createIdentity();
|
|
270
|
-
const space = await client.spaces.create();
|
|
271
|
-
client.addTypes([SheetType]);
|
|
272
|
-
|
|
273
|
-
const graph = graphs[space.id] ?? createComputeGraph();
|
|
274
|
-
if (!graphs[space.id]) {
|
|
275
|
-
setGraph(space.id, graph);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const sheet = await createTestSheet({ graph });
|
|
279
|
-
space.db.add(sheet);
|
|
280
|
-
setSheet(sheet);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
return () => clearTimeout(t);
|
|
284
|
-
}, []);
|
|
285
|
-
|
|
286
|
-
return sheet;
|
|
287
|
-
};
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
} from './grid';
|
|
61
61
|
import { type GridSize, handleArrowNav, handleNav, useRangeSelect } from './nav';
|
|
62
62
|
import { type SheetContextProps, SheetContextProvider, useSheetContext } from './sheet-context';
|
|
63
|
+
import { useThreads } from './threads';
|
|
63
64
|
import { getRectUnion, getRelativeClientRect, scrollIntoView } from './util';
|
|
64
65
|
import {
|
|
65
66
|
type CellIndex,
|
|
@@ -68,7 +69,9 @@ import {
|
|
|
68
69
|
columnLetter,
|
|
69
70
|
posEquals,
|
|
70
71
|
rangeToA1Notation,
|
|
71
|
-
|
|
72
|
+
addressToIndex,
|
|
73
|
+
addressFromIndex,
|
|
74
|
+
} from '../../defs';
|
|
72
75
|
import {
|
|
73
76
|
CellEditor,
|
|
74
77
|
type CellRangeNotifier,
|
|
@@ -135,12 +138,16 @@ const SheetRoot = ({ children, ...props }: PropsWithChildren<SheetContextProps>)
|
|
|
135
138
|
|
|
136
139
|
type SheetMainProps = ThemedClassName<Partial<GridSize>>;
|
|
137
140
|
|
|
138
|
-
const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numRows,
|
|
141
|
+
const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numRows, numCols }, forwardRef) => {
|
|
139
142
|
const { model, cursor, setCursor, setRange, setEditing } = useSheetContext();
|
|
140
143
|
|
|
141
144
|
// Scrolling.
|
|
142
145
|
const { rowsRef, columnsRef, contentRef } = useScrollHandlers();
|
|
143
146
|
|
|
147
|
+
// Threads.
|
|
148
|
+
// TODO(Zan): Move this to an extension once we have an extension model.
|
|
149
|
+
useThreads();
|
|
150
|
+
|
|
144
151
|
//
|
|
145
152
|
// Order of Row/columns.
|
|
146
153
|
//
|
|
@@ -170,21 +177,21 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
170
177
|
}, [rows, columns]);
|
|
171
178
|
|
|
172
179
|
const handleMoveRows: SheetRowsProps['onMove'] = (from, to, num = 1) => {
|
|
173
|
-
const cursorIdx = cursor ? model.
|
|
180
|
+
const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : undefined;
|
|
174
181
|
const [rows] = model.sheet.rows.splice(from, num);
|
|
175
182
|
model.sheet.rows.splice(to, 0, rows);
|
|
176
183
|
if (cursorIdx) {
|
|
177
|
-
setCursor(model.
|
|
184
|
+
setCursor(addressFromIndex(model.sheet, cursorIdx));
|
|
178
185
|
}
|
|
179
186
|
setRows([...model.sheet.rows]);
|
|
180
187
|
};
|
|
181
188
|
|
|
182
189
|
const handleMoveColumns: SheetColumnsProps['onMove'] = (from, to, num = 1) => {
|
|
183
|
-
const cursorIdx = cursor ? model.
|
|
190
|
+
const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : undefined;
|
|
184
191
|
const columns = model.sheet.columns.splice(from, num);
|
|
185
192
|
model.sheet.columns.splice(to, 0, ...columns);
|
|
186
193
|
if (cursorIdx) {
|
|
187
|
-
setCursor(model.
|
|
194
|
+
setCursor(addressFromIndex(model.sheet, cursorIdx));
|
|
188
195
|
}
|
|
189
196
|
setColumns([...model.sheet.columns]);
|
|
190
197
|
};
|
|
@@ -256,8 +263,8 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
256
263
|
ref={columnsRef}
|
|
257
264
|
columns={columns}
|
|
258
265
|
sizes={columnSizes}
|
|
259
|
-
selected={cursor?.
|
|
260
|
-
onSelect={(
|
|
266
|
+
selected={cursor?.col}
|
|
267
|
+
onSelect={(col) => setCursor(cursor?.col === col ? undefined : { row: -1, col })}
|
|
261
268
|
onResize={handleResizeColumn}
|
|
262
269
|
onMove={handleMoveColumns}
|
|
263
270
|
/>
|
|
@@ -267,13 +274,13 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
267
274
|
rows={rows}
|
|
268
275
|
sizes={rowSizes}
|
|
269
276
|
selected={cursor?.row}
|
|
270
|
-
onSelect={(row) => setCursor(cursor?.row === row ? undefined : { row,
|
|
277
|
+
onSelect={(row) => setCursor(cursor?.row === row ? undefined : { row, col: -1 })}
|
|
271
278
|
onResize={handleResizeRow}
|
|
272
279
|
onMove={handleMoveRows}
|
|
273
280
|
/>
|
|
274
281
|
<SheetGrid
|
|
275
282
|
ref={contentRef}
|
|
276
|
-
size={{ numRows: numRows ?? rows.length,
|
|
283
|
+
size={{ numRows: numRows ?? rows.length, numCols: numCols ?? columns.length }}
|
|
277
284
|
rows={rows}
|
|
278
285
|
columns={columns}
|
|
279
286
|
rowSizes={rowSizes}
|
|
@@ -878,11 +885,11 @@ const SheetGrid = forwardRef<HTMLDivElement, SheetGridProps>(
|
|
|
878
885
|
|
|
879
886
|
{/* Grid cells. */}
|
|
880
887
|
{rowRange.map(({ row, top, height }) => {
|
|
881
|
-
return columnRange.map(({
|
|
888
|
+
return columnRange.map(({ col, left, width }) => {
|
|
882
889
|
const style: CSSProperties = { position: 'absolute', top, left, width, height };
|
|
883
|
-
const cell = { row,
|
|
890
|
+
const cell: CellAddress = { row, col };
|
|
884
891
|
const id = addressToA1Notation(cell);
|
|
885
|
-
const idx = model.
|
|
892
|
+
const idx = addressToIndex(model.sheet, cell);
|
|
886
893
|
const active = posEquals(cursor, cell);
|
|
887
894
|
if (active && editing) {
|
|
888
895
|
const value = initialText.current ?? model.getCellText(cell) ?? '';
|
|
@@ -1003,16 +1010,46 @@ type SheetCellProps = {
|
|
|
1003
1010
|
};
|
|
1004
1011
|
|
|
1005
1012
|
const SheetCell = ({ id, cell, style, active, onSelect }: SheetCellProps) => {
|
|
1006
|
-
const {
|
|
1013
|
+
const {
|
|
1014
|
+
formatting,
|
|
1015
|
+
editing,
|
|
1016
|
+
setRange,
|
|
1017
|
+
decorations,
|
|
1018
|
+
model: { sheet },
|
|
1019
|
+
} = useSheetContext();
|
|
1007
1020
|
const { value, classNames } = formatting.getFormatting(cell);
|
|
1008
1021
|
|
|
1022
|
+
const decorationsForCell = decorations.getDecorationsForCell(addressToIndex(sheet, cell)) ?? [];
|
|
1023
|
+
const decorationAddedClasses = useMemo(
|
|
1024
|
+
() => decorationsForCell.flatMap((d) => d.classNames ?? []),
|
|
1025
|
+
[decorationsForCell],
|
|
1026
|
+
);
|
|
1027
|
+
const decoratedContent = decorationsForCell.reduce(
|
|
1028
|
+
(children, { decorate }) => {
|
|
1029
|
+
if (!decorate) {
|
|
1030
|
+
return children;
|
|
1031
|
+
}
|
|
1032
|
+
const DecoratorComponent = decorate;
|
|
1033
|
+
return <DecoratorComponent>{children}</DecoratorComponent>;
|
|
1034
|
+
},
|
|
1035
|
+
<div
|
|
1036
|
+
role='none'
|
|
1037
|
+
className={mx(
|
|
1038
|
+
'flex flex-grow bs-full is-full px-2 items-center truncate cursor-pointer',
|
|
1039
|
+
...decorationAddedClasses,
|
|
1040
|
+
)}
|
|
1041
|
+
>
|
|
1042
|
+
{value}
|
|
1043
|
+
</div>,
|
|
1044
|
+
);
|
|
1045
|
+
|
|
1009
1046
|
return (
|
|
1010
1047
|
<div
|
|
1011
1048
|
{...{ [`data-${CELL_DATA_KEY}`]: id }}
|
|
1012
1049
|
role='cell'
|
|
1013
1050
|
style={style}
|
|
1014
1051
|
className={mx(
|
|
1015
|
-
'
|
|
1052
|
+
'border border-gridLine cursor-pointer',
|
|
1016
1053
|
fragments.cell,
|
|
1017
1054
|
active && ['z-20', fragments.cellSelected],
|
|
1018
1055
|
classNames,
|
|
@@ -1026,7 +1063,7 @@ const SheetCell = ({ id, cell, style, active, onSelect }: SheetCellProps) => {
|
|
|
1026
1063
|
}}
|
|
1027
1064
|
onDoubleClick={() => onSelect?.(cell, true)}
|
|
1028
1065
|
>
|
|
1029
|
-
{
|
|
1066
|
+
{decoratedContent}
|
|
1030
1067
|
</div>
|
|
1031
1068
|
);
|
|
1032
1069
|
};
|
|
@@ -1045,10 +1082,11 @@ const GridCellEditor = ({ style, value, onNav, onClose }: GridCellEditorProps) =
|
|
|
1045
1082
|
notifier.current?.(rangeToA1Notation(range));
|
|
1046
1083
|
}
|
|
1047
1084
|
}, [range]);
|
|
1085
|
+
|
|
1048
1086
|
const extension = useMemo(
|
|
1049
1087
|
() => [
|
|
1050
1088
|
editorKeys({ onNav, onClose }),
|
|
1051
|
-
sheetExtension({ functions: model.
|
|
1089
|
+
sheetExtension({ functions: model.graph.getFunctions() }),
|
|
1052
1090
|
rangeExtension((fn) => (notifier.current = fn)),
|
|
1053
1091
|
],
|
|
1054
1092
|
[model],
|
|
@@ -1072,12 +1110,13 @@ const GridCellEditor = ({ style, value, onNav, onClose }: GridCellEditorProps) =
|
|
|
1072
1110
|
|
|
1073
1111
|
const SheetStatusBar = () => {
|
|
1074
1112
|
const { model, cursor, range } = useSheetContext();
|
|
1113
|
+
|
|
1075
1114
|
let value;
|
|
1076
1115
|
let isFormula = false;
|
|
1077
1116
|
if (cursor) {
|
|
1078
1117
|
value = model.getCellValue(cursor);
|
|
1079
1118
|
if (typeof value === 'string' && value.charAt(0) === '=') {
|
|
1080
|
-
value = model.
|
|
1119
|
+
value = model.graph.mapFunctionBindingFromId(model.mapFormulaIndicesToRefs(value));
|
|
1081
1120
|
isFormula = true;
|
|
1082
1121
|
} else if (value != null) {
|
|
1083
1122
|
value = String(value);
|