@dxos/plugin-sheet 0.6.11-staging.e6894a4 → 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-P7SSL3EG.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-4XOKHKKZ.mjs → chunk-U2JHW3L6.mjs} +1043 -261
- 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 +80 -66
- 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-SVAIIXWQ.cjs → chunk-DD6FIXWC.cjs} +360 -667
- package/dist/lib/node/chunk-DD6FIXWC.cjs.map +7 -0
- package/dist/lib/node/{SheetContainer-IQT6TR4Z.cjs → chunk-OTTD7FBK.cjs} +1062 -289
- 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 +93 -72
- 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 +51 -72
- 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 +48 -87
- package/src/components/Sheet/Sheet.tsx +69 -39
- 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 -21
- package/src/components/Toolbar/Toolbar.stories.tsx +5 -10
- 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-4XOKHKKZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-FUAGSXA4.mjs.map +0 -7
- package/dist/lib/browser/chunk-FWGRE3EG.mjs +0 -175
- package/dist/lib/browser/chunk-FWGRE3EG.mjs.map +0 -7
- package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +0 -7
- package/dist/lib/browser/chunk-P7SSL3EG.mjs.map +0 -7
- package/dist/lib/browser/chunk-YPU3R7FA.mjs +0 -8
- package/dist/lib/browser/chunk-YPU3R7FA.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-IQT6TR4Z.cjs.map +0 -7
- package/dist/lib/node/chunk-5EPCDAZC.cjs +0 -40
- package/dist/lib/node/chunk-5EPCDAZC.cjs.map +0 -7
- package/dist/lib/node/chunk-727C6YNP.cjs +0 -202
- package/dist/lib/node/chunk-727C6YNP.cjs.map +0 -7
- package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +0 -7
- package/dist/lib/node/chunk-DSYKOI4E.cjs.map +0 -7
- package/dist/lib/node/chunk-SVAIIXWQ.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 -551
- 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
|
@@ -40,7 +40,7 @@ import { debounce } from '@dxos/async';
|
|
|
40
40
|
import { fullyQualifiedId, createDocAccessor } from '@dxos/client/echo';
|
|
41
41
|
import { log } from '@dxos/log';
|
|
42
42
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
43
|
-
import { createAttendableAttributes } from '@dxos/react-ui-attention';
|
|
43
|
+
import { createAttendableAttributes, useHasAttention } from '@dxos/react-ui-attention';
|
|
44
44
|
import { mx } from '@dxos/react-ui-theme';
|
|
45
45
|
|
|
46
46
|
import {
|
|
@@ -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,
|
|
@@ -112,13 +115,11 @@ import {
|
|
|
112
115
|
* - Update formula ranges by selection.
|
|
113
116
|
*/
|
|
114
117
|
|
|
115
|
-
// TODO(burdon): Factor out fragments.
|
|
116
118
|
const fragments = {
|
|
117
119
|
axis: 'bg-axisSurface text-axisText text-xs select-none',
|
|
118
120
|
axisSelected: 'bg-attention text-baseText',
|
|
119
121
|
cell: 'bg-gridCell',
|
|
120
122
|
cellSelected: 'bg-gridCellSelected text-baseText border !border-accentSurface',
|
|
121
|
-
border: 'border-gridLine',
|
|
122
123
|
};
|
|
123
124
|
|
|
124
125
|
//
|
|
@@ -137,12 +138,16 @@ const SheetRoot = ({ children, ...props }: PropsWithChildren<SheetContextProps>)
|
|
|
137
138
|
|
|
138
139
|
type SheetMainProps = ThemedClassName<Partial<GridSize>>;
|
|
139
140
|
|
|
140
|
-
const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numRows,
|
|
141
|
+
const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numRows, numCols }, forwardRef) => {
|
|
141
142
|
const { model, cursor, setCursor, setRange, setEditing } = useSheetContext();
|
|
142
143
|
|
|
143
144
|
// Scrolling.
|
|
144
145
|
const { rowsRef, columnsRef, contentRef } = useScrollHandlers();
|
|
145
146
|
|
|
147
|
+
// Threads.
|
|
148
|
+
// TODO(Zan): Move this to an extension once we have an extension model.
|
|
149
|
+
useThreads();
|
|
150
|
+
|
|
146
151
|
//
|
|
147
152
|
// Order of Row/columns.
|
|
148
153
|
//
|
|
@@ -172,21 +177,21 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
172
177
|
}, [rows, columns]);
|
|
173
178
|
|
|
174
179
|
const handleMoveRows: SheetRowsProps['onMove'] = (from, to, num = 1) => {
|
|
175
|
-
const cursorIdx = cursor ? model.
|
|
180
|
+
const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : undefined;
|
|
176
181
|
const [rows] = model.sheet.rows.splice(from, num);
|
|
177
182
|
model.sheet.rows.splice(to, 0, rows);
|
|
178
183
|
if (cursorIdx) {
|
|
179
|
-
setCursor(model.
|
|
184
|
+
setCursor(addressFromIndex(model.sheet, cursorIdx));
|
|
180
185
|
}
|
|
181
186
|
setRows([...model.sheet.rows]);
|
|
182
187
|
};
|
|
183
188
|
|
|
184
189
|
const handleMoveColumns: SheetColumnsProps['onMove'] = (from, to, num = 1) => {
|
|
185
|
-
const cursorIdx = cursor ? model.
|
|
190
|
+
const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : undefined;
|
|
186
191
|
const columns = model.sheet.columns.splice(from, num);
|
|
187
192
|
model.sheet.columns.splice(to, 0, ...columns);
|
|
188
193
|
if (cursorIdx) {
|
|
189
|
-
setCursor(model.
|
|
194
|
+
setCursor(addressFromIndex(model.sheet, cursorIdx));
|
|
190
195
|
}
|
|
191
196
|
setColumns([...model.sheet.columns]);
|
|
192
197
|
};
|
|
@@ -244,7 +249,6 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
244
249
|
role='none'
|
|
245
250
|
className={mx(
|
|
246
251
|
'grid grid-cols-[calc(var(--rail-size)-2px)_1fr] grid-rows-[32px_1fr_32px] bs-full is-full overflow-hidden',
|
|
247
|
-
fragments.border,
|
|
248
252
|
classNames,
|
|
249
253
|
)}
|
|
250
254
|
>
|
|
@@ -259,8 +263,8 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
259
263
|
ref={columnsRef}
|
|
260
264
|
columns={columns}
|
|
261
265
|
sizes={columnSizes}
|
|
262
|
-
selected={cursor?.
|
|
263
|
-
onSelect={(
|
|
266
|
+
selected={cursor?.col}
|
|
267
|
+
onSelect={(col) => setCursor(cursor?.col === col ? undefined : { row: -1, col })}
|
|
264
268
|
onResize={handleResizeColumn}
|
|
265
269
|
onMove={handleMoveColumns}
|
|
266
270
|
/>
|
|
@@ -270,13 +274,13 @@ const SheetMain = forwardRef<HTMLDivElement, SheetMainProps>(({ classNames, numR
|
|
|
270
274
|
rows={rows}
|
|
271
275
|
sizes={rowSizes}
|
|
272
276
|
selected={cursor?.row}
|
|
273
|
-
onSelect={(row) => setCursor(cursor?.row === row ? undefined : { row,
|
|
277
|
+
onSelect={(row) => setCursor(cursor?.row === row ? undefined : { row, col: -1 })}
|
|
274
278
|
onResize={handleResizeRow}
|
|
275
279
|
onMove={handleMoveRows}
|
|
276
280
|
/>
|
|
277
281
|
<SheetGrid
|
|
278
282
|
ref={contentRef}
|
|
279
|
-
size={{ numRows: numRows ?? rows.length,
|
|
283
|
+
size={{ numRows: numRows ?? rows.length, numCols: numCols ?? columns.length }}
|
|
280
284
|
rows={rows}
|
|
281
285
|
columns={columns}
|
|
282
286
|
rowSizes={rowSizes}
|
|
@@ -425,7 +429,7 @@ const SheetRows = forwardRef<HTMLDivElement, SheetRowsProps>(
|
|
|
425
429
|
<div className='relative flex grow overflow-hidden'>
|
|
426
430
|
{/* Fixed border. */}
|
|
427
431
|
<div
|
|
428
|
-
className={mx('z-20 absolute inset-0 border-y pointer-events-none'
|
|
432
|
+
className={mx('z-20 absolute inset-0 border-y border-gridLine pointer-events-none')}
|
|
429
433
|
style={{ width: axisWidth }}
|
|
430
434
|
/>
|
|
431
435
|
|
|
@@ -520,8 +524,7 @@ const GridRowCell = ({ idx, index, label, size, resize, selected, onSelect, onRe
|
|
|
520
524
|
{...listeners}
|
|
521
525
|
className={mx(
|
|
522
526
|
'flex h-full items-center justify-center cursor-pointer',
|
|
523
|
-
'border-t focus-visible:outline-none',
|
|
524
|
-
fragments.border,
|
|
527
|
+
'border-t border-gridLine focus-visible:outline-none',
|
|
525
528
|
fragments.axis,
|
|
526
529
|
selected && fragments.axisSelected,
|
|
527
530
|
isDragging && fragments.axisSelected,
|
|
@@ -588,7 +591,7 @@ const SheetColumns = forwardRef<HTMLDivElement, SheetColumnsProps>(
|
|
|
588
591
|
<div className='relative flex grow overflow-hidden'>
|
|
589
592
|
{/* Fixed border. */}
|
|
590
593
|
<div
|
|
591
|
-
className={mx('z-20 absolute inset-0 border-x pointer-events-none'
|
|
594
|
+
className={mx('z-20 absolute inset-0 border-x border-gridLine pointer-events-none')}
|
|
592
595
|
style={{ height: axisHeight }}
|
|
593
596
|
/>
|
|
594
597
|
|
|
@@ -684,8 +687,7 @@ const GridColumnCell = ({ idx, index, label, size, resize, selected, onSelect, o
|
|
|
684
687
|
{...listeners}
|
|
685
688
|
className={mx(
|
|
686
689
|
'flex h-full items-center justify-center cursor-pointer',
|
|
687
|
-
'border-l focus-visible:outline-none',
|
|
688
|
-
fragments.border,
|
|
690
|
+
'border-l border-gridLine focus-visible:outline-none',
|
|
689
691
|
fragments.axis,
|
|
690
692
|
selected && fragments.axisSelected,
|
|
691
693
|
isDragging && fragments.axisSelected,
|
|
@@ -860,18 +862,17 @@ const SheetGrid = forwardRef<HTMLDivElement, SheetGridProps>(
|
|
|
860
862
|
});
|
|
861
863
|
|
|
862
864
|
// TODO(burdon): Prevent scroll if not attended.
|
|
863
|
-
const
|
|
864
|
-
const attendableAttrs = createAttendableAttributes(
|
|
865
|
-
|
|
866
|
-
const attended = true;
|
|
865
|
+
const id = fullyQualifiedId(model.sheet);
|
|
866
|
+
const attendableAttrs = createAttendableAttributes(id);
|
|
867
|
+
const hasAttention = useHasAttention(id);
|
|
867
868
|
|
|
868
869
|
return (
|
|
869
870
|
<div ref={containerRef} role='grid' className='relative flex grow overflow-hidden'>
|
|
870
871
|
{/* Fixed border. */}
|
|
871
|
-
<div className={mx('z-20 absolute inset-0 border pointer-events-none'
|
|
872
|
+
<div className={mx('z-20 absolute inset-0 border border-gridLine pointer-events-none')} />
|
|
872
873
|
|
|
873
874
|
{/* Grid scroll container. */}
|
|
874
|
-
<div ref={scrollerRef} className={mx('grow',
|
|
875
|
+
<div ref={scrollerRef} className={mx('grow', hasAttention && 'overflow-auto scrollbar-thin')}>
|
|
875
876
|
{/* Scroll content. */}
|
|
876
877
|
<div
|
|
877
878
|
className='relative select-none'
|
|
@@ -884,11 +885,11 @@ const SheetGrid = forwardRef<HTMLDivElement, SheetGridProps>(
|
|
|
884
885
|
|
|
885
886
|
{/* Grid cells. */}
|
|
886
887
|
{rowRange.map(({ row, top, height }) => {
|
|
887
|
-
return columnRange.map(({
|
|
888
|
+
return columnRange.map(({ col, left, width }) => {
|
|
888
889
|
const style: CSSProperties = { position: 'absolute', top, left, width, height };
|
|
889
|
-
const cell = { row,
|
|
890
|
+
const cell: CellAddress = { row, col };
|
|
890
891
|
const id = addressToA1Notation(cell);
|
|
891
|
-
const idx = model.
|
|
892
|
+
const idx = addressToIndex(model.sheet, cell);
|
|
892
893
|
const active = posEquals(cursor, cell);
|
|
893
894
|
if (active && editing) {
|
|
894
895
|
const value = initialText.current ?? model.getCellText(cell) ?? '';
|
|
@@ -1009,19 +1010,47 @@ type SheetCellProps = {
|
|
|
1009
1010
|
};
|
|
1010
1011
|
|
|
1011
1012
|
const SheetCell = ({ id, cell, style, active, onSelect }: SheetCellProps) => {
|
|
1012
|
-
const {
|
|
1013
|
+
const {
|
|
1014
|
+
formatting,
|
|
1015
|
+
editing,
|
|
1016
|
+
setRange,
|
|
1017
|
+
decorations,
|
|
1018
|
+
model: { sheet },
|
|
1019
|
+
} = useSheetContext();
|
|
1013
1020
|
const { value, classNames } = formatting.getFormatting(cell);
|
|
1014
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
|
+
|
|
1015
1046
|
return (
|
|
1016
1047
|
<div
|
|
1017
1048
|
{...{ [`data-${CELL_DATA_KEY}`]: id }}
|
|
1018
1049
|
role='cell'
|
|
1019
1050
|
style={style}
|
|
1020
1051
|
className={mx(
|
|
1021
|
-
'
|
|
1022
|
-
'px-2 py-1',
|
|
1052
|
+
'border border-gridLine cursor-pointer',
|
|
1023
1053
|
fragments.cell,
|
|
1024
|
-
fragments.border,
|
|
1025
1054
|
active && ['z-20', fragments.cellSelected],
|
|
1026
1055
|
classNames,
|
|
1027
1056
|
)}
|
|
@@ -1034,7 +1063,7 @@ const SheetCell = ({ id, cell, style, active, onSelect }: SheetCellProps) => {
|
|
|
1034
1063
|
}}
|
|
1035
1064
|
onDoubleClick={() => onSelect?.(cell, true)}
|
|
1036
1065
|
>
|
|
1037
|
-
{
|
|
1066
|
+
{decoratedContent}
|
|
1038
1067
|
</div>
|
|
1039
1068
|
);
|
|
1040
1069
|
};
|
|
@@ -1053,10 +1082,11 @@ const GridCellEditor = ({ style, value, onNav, onClose }: GridCellEditorProps) =
|
|
|
1053
1082
|
notifier.current?.(rangeToA1Notation(range));
|
|
1054
1083
|
}
|
|
1055
1084
|
}, [range]);
|
|
1085
|
+
|
|
1056
1086
|
const extension = useMemo(
|
|
1057
1087
|
() => [
|
|
1058
1088
|
editorKeys({ onNav, onClose }),
|
|
1059
|
-
sheetExtension({ functions: model.
|
|
1089
|
+
sheetExtension({ functions: model.graph.getFunctions() }),
|
|
1060
1090
|
rangeExtension((fn) => (notifier.current = fn)),
|
|
1061
1091
|
],
|
|
1062
1092
|
[model],
|
|
@@ -1080,12 +1110,13 @@ const GridCellEditor = ({ style, value, onNav, onClose }: GridCellEditorProps) =
|
|
|
1080
1110
|
|
|
1081
1111
|
const SheetStatusBar = () => {
|
|
1082
1112
|
const { model, cursor, range } = useSheetContext();
|
|
1113
|
+
|
|
1083
1114
|
let value;
|
|
1084
1115
|
let isFormula = false;
|
|
1085
1116
|
if (cursor) {
|
|
1086
1117
|
value = model.getCellValue(cursor);
|
|
1087
1118
|
if (typeof value === 'string' && value.charAt(0) === '=') {
|
|
1088
|
-
value = model.
|
|
1119
|
+
value = model.graph.mapFunctionBindingFromId(model.mapFormulaIndicesToRefs(value));
|
|
1089
1120
|
isFormula = true;
|
|
1090
1121
|
} else if (value != null) {
|
|
1091
1122
|
value = String(value);
|
|
@@ -1093,7 +1124,7 @@ const SheetStatusBar = () => {
|
|
|
1093
1124
|
}
|
|
1094
1125
|
|
|
1095
1126
|
return (
|
|
1096
|
-
<div className={mx('flex shrink-0 justify-between items-center px-4 py-1 text-sm border-x
|
|
1127
|
+
<div className={mx('flex shrink-0 justify-between items-center px-4 py-1 text-sm border-x border-gridLine')}>
|
|
1097
1128
|
<div className='flex gap-4 items-center'>
|
|
1098
1129
|
<div className='flex w-16 items-center font-mono'>
|
|
1099
1130
|
{(range && rangeToA1Notation(range)) || (cursor && addressToA1Notation(cursor))}
|
|
@@ -1129,8 +1160,7 @@ const SheetDebug = () => {
|
|
|
1129
1160
|
<div
|
|
1130
1161
|
className={mx(
|
|
1131
1162
|
'z-20 absolute right-0 top-20 bottom-20 w-[30rem] overflow-auto scrollbar-thin',
|
|
1132
|
-
'border text-xs bg-neutral-50 dark:bg-black text-cyan-500 font-mono p-1 opacity-80',
|
|
1133
|
-
fragments.border,
|
|
1163
|
+
'border border-gridLine text-xs bg-neutral-50 dark:bg-black text-cyan-500 font-mono p-1 opacity-80',
|
|
1134
1164
|
)}
|
|
1135
1165
|
>
|
|
1136
1166
|
<pre className='whitespace-pre-wrap'>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { create } from '@dxos/echo-schema';
|
|
6
|
+
|
|
7
|
+
export type Decoration = {
|
|
8
|
+
type: string;
|
|
9
|
+
/**
|
|
10
|
+
* A wrapping render function to encapsulate cell content. This function is applied between
|
|
11
|
+
* the cell's border and its padding/layout/content, allowing for custom rendering or
|
|
12
|
+
* additional elements to be inserted around the cell's main content.
|
|
13
|
+
*/
|
|
14
|
+
decorate?: (props: { children: React.ReactNode }) => React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* An array of CSS class names to be applied to the content of the SheetCell.
|
|
17
|
+
* These classes can be used to style the cell's content independently of its structure.
|
|
18
|
+
*/
|
|
19
|
+
classNames?: string[];
|
|
20
|
+
cellIndex: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const createDecorations = () => {
|
|
24
|
+
// Reactive object to hold decorations
|
|
25
|
+
// TODO(Zan): Use CELL ID's to key the decoration map.
|
|
26
|
+
// TODO(Zan): Consider maintaining an index of decorations by type.
|
|
27
|
+
const { decorations } = create<{ decorations: Record<string, Decoration[]> }>({ decorations: {} });
|
|
28
|
+
|
|
29
|
+
const addDecoration = (cellIndex: string, decorator: Decoration) => {
|
|
30
|
+
decorations[cellIndex] = [...(decorations[cellIndex] || []), decorator];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const removeDecoration = (cellIndex: string, type?: string) => {
|
|
34
|
+
if (type) {
|
|
35
|
+
decorations[cellIndex] = (decorations[cellIndex] || []).filter((d) => d.type !== type);
|
|
36
|
+
} else {
|
|
37
|
+
delete decorations[cellIndex];
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// TODO(Zan): I should check if returning the a value from a map in a deep signal is a reactive slice.
|
|
42
|
+
const getDecorationsForCell = (cellIndex: string): Decoration[] | undefined => {
|
|
43
|
+
return decorations[cellIndex];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getAllDecorations = (): Decoration[] => {
|
|
47
|
+
const result: Decoration[] = [];
|
|
48
|
+
for (const decoratorArray of Object.values(decorations)) {
|
|
49
|
+
for (const decorator of decoratorArray) {
|
|
50
|
+
result.push(decorator);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
addDecoration,
|
|
58
|
+
removeDecoration,
|
|
59
|
+
getDecorationsForCell,
|
|
60
|
+
getAllDecorations,
|
|
61
|
+
} as const;
|
|
62
|
+
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { type MouseEvent, useEffect, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { type CellAddress, type CellIndex, addressFromA1Notation, addressToA1Notation } from '../../
|
|
7
|
+
import { type CellAddress, type CellIndex, addressFromA1Notation, addressToA1Notation } from '../../defs';
|
|
8
8
|
|
|
9
9
|
// export type Bounds = Pick<DOMRect, 'left' | 'top' | 'width' | 'height'>;
|
|
10
10
|
// export type Dimension = Pick<DOMRect, 'width' | 'height'>;
|
|
@@ -12,7 +12,7 @@ import { type CellAddress, type CellIndex, addressFromA1Notation, addressToA1Not
|
|
|
12
12
|
export type SizeMap = Record<string, number>;
|
|
13
13
|
|
|
14
14
|
export type RowPosition = { row: number } & Pick<DOMRect, 'top' | 'height'>;
|
|
15
|
-
export type ColumnPosition = {
|
|
15
|
+
export type ColumnPosition = { col: number } & Pick<DOMRect, 'left' | 'width'>;
|
|
16
16
|
|
|
17
17
|
export const axisWidth = 'calc(var(--rail-size)-2px)';
|
|
18
18
|
export const axisHeight = 34;
|
|
@@ -88,7 +88,7 @@ export const useGridLayout = ({
|
|
|
88
88
|
const width = columnSizes?.[idx] ?? defaultWidth;
|
|
89
89
|
const left = x;
|
|
90
90
|
x += width - 1;
|
|
91
|
-
return {
|
|
91
|
+
return { col: i, left, width };
|
|
92
92
|
}),
|
|
93
93
|
);
|
|
94
94
|
}, [columns, columnSizes]);
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
import { type KeyboardEvent, type MouseEventHandler, useState } from 'react';
|
|
6
6
|
|
|
7
7
|
import { getCellAtPointer } from './grid';
|
|
8
|
-
import { type CellAddress, type CellRange, posEquals } from '../../
|
|
8
|
+
import { type CellAddress, type CellRange, posEquals } from '../../defs';
|
|
9
9
|
|
|
10
10
|
export type GridSize = {
|
|
11
11
|
numRows: number;
|
|
12
|
-
|
|
12
|
+
numCols: number;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
/**
|
|
@@ -38,14 +38,14 @@ export const handleNav = (
|
|
|
38
38
|
break;
|
|
39
39
|
}
|
|
40
40
|
case 'ArrowLeft': {
|
|
41
|
-
if (opposite.
|
|
42
|
-
opposite.
|
|
41
|
+
if (opposite.col > 0) {
|
|
42
|
+
opposite.col -= 1;
|
|
43
43
|
}
|
|
44
44
|
break;
|
|
45
45
|
}
|
|
46
46
|
case 'ArrowRight': {
|
|
47
|
-
if (opposite.
|
|
48
|
-
opposite.
|
|
47
|
+
if (opposite.col < size.numCols - 1) {
|
|
48
|
+
opposite.col += 1;
|
|
49
49
|
}
|
|
50
50
|
break;
|
|
51
51
|
}
|
|
@@ -64,41 +64,41 @@ export const handleNav = (
|
|
|
64
64
|
export const handleArrowNav = (
|
|
65
65
|
ev: Pick<KeyboardEvent<HTMLInputElement>, 'key' | 'metaKey'>,
|
|
66
66
|
cursor: CellAddress | undefined,
|
|
67
|
-
{ numRows,
|
|
67
|
+
{ numRows, numCols }: GridSize,
|
|
68
68
|
): CellAddress | undefined => {
|
|
69
69
|
switch (ev.key) {
|
|
70
70
|
case 'ArrowUp':
|
|
71
71
|
if (cursor === undefined) {
|
|
72
|
-
return { row: 0,
|
|
72
|
+
return { row: 0, col: 0 };
|
|
73
73
|
} else if (cursor.row > 0) {
|
|
74
|
-
return { row: ev.metaKey ? 0 : cursor.row - 1,
|
|
74
|
+
return { row: ev.metaKey ? 0 : cursor.row - 1, col: cursor.col };
|
|
75
75
|
}
|
|
76
76
|
break;
|
|
77
77
|
case 'ArrowDown':
|
|
78
78
|
if (cursor === undefined) {
|
|
79
|
-
return { row: 0,
|
|
79
|
+
return { row: 0, col: 0 };
|
|
80
80
|
} else if (cursor.row < numRows - 1) {
|
|
81
|
-
return { row: ev.metaKey ? numRows - 1 : cursor.row + 1,
|
|
81
|
+
return { row: ev.metaKey ? numRows - 1 : cursor.row + 1, col: cursor.col };
|
|
82
82
|
}
|
|
83
83
|
break;
|
|
84
84
|
case 'ArrowLeft':
|
|
85
85
|
if (cursor === undefined) {
|
|
86
|
-
return { row: 0,
|
|
87
|
-
} else if (cursor.
|
|
88
|
-
return { row: cursor.row,
|
|
86
|
+
return { row: 0, col: 0 };
|
|
87
|
+
} else if (cursor.col > 0) {
|
|
88
|
+
return { row: cursor.row, col: ev.metaKey ? 0 : cursor.col - 1 };
|
|
89
89
|
}
|
|
90
90
|
break;
|
|
91
91
|
case 'ArrowRight':
|
|
92
92
|
if (cursor === undefined) {
|
|
93
|
-
return { row: 0,
|
|
94
|
-
} else if (cursor.
|
|
95
|
-
return { row: cursor.row,
|
|
93
|
+
return { row: 0, col: 0 };
|
|
94
|
+
} else if (cursor.col < numCols - 1) {
|
|
95
|
+
return { row: cursor.row, col: ev.metaKey ? numCols - 1 : cursor.col + 1 };
|
|
96
96
|
}
|
|
97
97
|
break;
|
|
98
98
|
case 'Home':
|
|
99
|
-
return { row: 0,
|
|
99
|
+
return { row: 0, col: 0 };
|
|
100
100
|
case 'End':
|
|
101
|
-
return { row: numRows - 1,
|
|
101
|
+
return { row: numRows - 1, col: numCols - 1 };
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
104
|
|
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { type PropsWithChildren, createContext, useContext,
|
|
5
|
+
import React, { type PropsWithChildren, createContext, useContext, useMemo, useState } from 'react';
|
|
6
6
|
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
|
-
import { type
|
|
9
|
-
import { fullyQualifiedId, type Space } from '@dxos/react-client/echo';
|
|
8
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
10
9
|
|
|
11
|
-
import {
|
|
12
|
-
import { type CellAddress, type CellRange
|
|
10
|
+
import { createDecorations } from './decorations';
|
|
11
|
+
import { type CellAddress, type CellRange } from '../../defs';
|
|
12
|
+
import { useSheetModel, useFormattingModel } from '../../hooks';
|
|
13
|
+
import { type FormattingModel, type SheetModel } from '../../model';
|
|
13
14
|
import { type SheetType } from '../../types';
|
|
14
|
-
import { type FunctionContextOptions } from '../ComputeGraph';
|
|
15
|
-
// TODO(wittjosiah): Refactor. This is not exported from ./components due to depending on ECHO.
|
|
16
|
-
import { useComputeGraph } from '../ComputeGraph/graph-context';
|
|
17
|
-
|
|
18
|
-
// TODO(wittjosiah): Factor out.
|
|
19
|
-
const OBJECT_ID_LENGTH = 60; // 33 (space id) + 26 (object id) + 1 (separator).
|
|
20
15
|
|
|
21
16
|
export type SheetContextType = {
|
|
22
17
|
model: SheetModel;
|
|
@@ -36,6 +31,9 @@ export type SheetContextType = {
|
|
|
36
31
|
// Events.
|
|
37
32
|
// TODO(burdon): Generalize.
|
|
38
33
|
onInfo?: () => void;
|
|
34
|
+
|
|
35
|
+
// Decorations.
|
|
36
|
+
decorations: ReturnType<typeof createDecorations>;
|
|
39
37
|
};
|
|
40
38
|
|
|
41
39
|
const SheetContext = createContext<SheetContextType | null>(null);
|
|
@@ -50,49 +48,7 @@ export type SheetContextProps = {
|
|
|
50
48
|
sheet: SheetType;
|
|
51
49
|
space: Space;
|
|
52
50
|
readonly?: boolean;
|
|
53
|
-
} & Pick<SheetContextType, 'onInfo'
|
|
54
|
-
Partial<FunctionContextOptions>;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Map from binding to fully qualified ECHO ID.
|
|
58
|
-
*/
|
|
59
|
-
const mapFormulaBindingToId =
|
|
60
|
-
(functions: FunctionType[]) =>
|
|
61
|
-
(formula: string): string => {
|
|
62
|
-
return formula.replace(/([a-zA-Z0-9]+)\((.*)\)/g, (match, binding, args) => {
|
|
63
|
-
if (defaultFunctions.find((fn) => fn.name === binding) || binding === 'EDGE') {
|
|
64
|
-
return match;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const fn = functions.find((fn) => fn.binding === binding);
|
|
68
|
-
if (fn) {
|
|
69
|
-
return `${fullyQualifiedId(fn)}(${args})`;
|
|
70
|
-
} else {
|
|
71
|
-
return match;
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Map from fully qualified ECHO ID to binding.
|
|
78
|
-
*/
|
|
79
|
-
const mapFormulaBindingFromId =
|
|
80
|
-
(functions: FunctionType[]) =>
|
|
81
|
-
(formula: string): string => {
|
|
82
|
-
return formula.replace(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)\((.*)\)/g, (match, spaceId, objectId, args) => {
|
|
83
|
-
const id = `${spaceId}:${objectId}`;
|
|
84
|
-
if (id.length !== OBJECT_ID_LENGTH) {
|
|
85
|
-
return match;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const fn = functions.find((fn) => fullyQualifiedId(fn) === id);
|
|
89
|
-
if (fn?.binding) {
|
|
90
|
-
return `${fn.binding}(${args})`;
|
|
91
|
-
} else {
|
|
92
|
-
return match;
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
};
|
|
51
|
+
} & Pick<SheetContextType, 'onInfo'>;
|
|
96
52
|
|
|
97
53
|
export const SheetContextProvider = ({
|
|
98
54
|
children,
|
|
@@ -100,36 +56,17 @@ export const SheetContextProvider = ({
|
|
|
100
56
|
space,
|
|
101
57
|
readonly,
|
|
102
58
|
onInfo,
|
|
103
|
-
...options
|
|
104
59
|
}: PropsWithChildren<SheetContextProps>) => {
|
|
105
|
-
const
|
|
60
|
+
const model = useSheetModel(space, sheet, { readonly });
|
|
61
|
+
const formatting = useFormattingModel(model);
|
|
106
62
|
|
|
63
|
+
// TODO(Zan): Impl. set range and set cursor that scrolls to that cell or range if it is not visible.
|
|
107
64
|
const [cursor, setCursor] = useState<CellAddress>();
|
|
108
65
|
const [range, setRange] = useState<CellRange>();
|
|
109
66
|
const [editing, setEditing] = useState<boolean>(false);
|
|
67
|
+
const decorations = useMemo(() => createDecorations(), []);
|
|
110
68
|
|
|
111
|
-
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
let model: SheetModel | undefined;
|
|
114
|
-
let formatting;
|
|
115
|
-
const t = setTimeout(async () => {
|
|
116
|
-
model = new SheetModel(graph, sheet, space, { readonly, mapFormulaBindingToId, mapFormulaBindingFromId });
|
|
117
|
-
await model.initialize();
|
|
118
|
-
formatting = new FormattingModel(model);
|
|
119
|
-
setModels([model, formatting]);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
return () => {
|
|
123
|
-
clearTimeout(t);
|
|
124
|
-
void model?.destroy();
|
|
125
|
-
};
|
|
126
|
-
}, [graph, readonly]);
|
|
127
|
-
|
|
128
|
-
if (!model || !formatting) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return (
|
|
69
|
+
return !model || !formatting ? null : (
|
|
133
70
|
<SheetContext.Provider
|
|
134
71
|
value={{
|
|
135
72
|
model,
|
|
@@ -142,6 +79,7 @@ export const SheetContextProvider = ({
|
|
|
142
79
|
setEditing,
|
|
143
80
|
// TODO(burdon): Change to event.
|
|
144
81
|
onInfo,
|
|
82
|
+
decorations,
|
|
145
83
|
}}
|
|
146
84
|
>
|
|
147
85
|
{children}
|