@dxos/plugin-sheet 0.6.12-staging.e11e696 → 0.6.13-main.041e8aa
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-NDNIS44E.mjs +265 -0
- package/dist/lib/browser/SheetContainer-NDNIS44E.mjs.map +7 -0
- package/dist/lib/browser/chunk-AQSGDA4X.mjs +1614 -0
- package/dist/lib/browser/chunk-AQSGDA4X.mjs.map +7 -0
- package/dist/lib/browser/{chunk-QILRZNE5.mjs → chunk-D3QTX46O.mjs} +4 -5
- package/dist/lib/browser/chunk-D3QTX46O.mjs.map +7 -0
- package/dist/lib/browser/{chunk-WZMOZKQZ.mjs → chunk-GKI67SEF.mjs} +19 -25
- package/dist/lib/browser/chunk-GKI67SEF.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +14 -19
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types.mjs +4 -8
- package/dist/lib/node/SheetContainer-YSQGJD7K.cjs +276 -0
- package/dist/lib/node/SheetContainer-YSQGJD7K.cjs.map +7 -0
- package/dist/lib/node/chunk-6F43RV45.cjs +1610 -0
- package/dist/lib/node/chunk-6F43RV45.cjs.map +7 -0
- package/dist/lib/node/{chunk-AOP42UAA.cjs → chunk-ER3PM7GD.cjs} +25 -33
- package/dist/lib/node/chunk-ER3PM7GD.cjs.map +7 -0
- package/dist/lib/node/{chunk-BNARJ5GM.cjs → chunk-QIFIGEKV.cjs} +6 -7
- package/dist/lib/node/chunk-QIFIGEKV.cjs.map +7 -0
- package/dist/lib/node/index.cjs +36 -40
- package/dist/lib/node/index.cjs.map +4 -4
- 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 +8 -12
- package/dist/lib/node/types.cjs.map +2 -2
- package/dist/lib/node-esm/SheetContainer-M7WRMZDU.mjs +266 -0
- package/dist/lib/node-esm/SheetContainer-M7WRMZDU.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-ELTFPX5B.mjs +1615 -0
- package/dist/lib/node-esm/chunk-ELTFPX5B.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-IU2L277A.mjs → chunk-VCYJWE3O.mjs} +4 -5
- package/dist/lib/node-esm/chunk-VCYJWE3O.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-RR2AO4SM.mjs → chunk-ZVLLQ2PJ.mjs} +19 -25
- package/dist/lib/node-esm/chunk-ZVLLQ2PJ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +14 -19
- package/dist/lib/node-esm/index.mjs.map +4 -4
- 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 +4 -8
- package/dist/types/src/SheetPlugin.d.ts.map +1 -1
- package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts +3 -0
- package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts.map +1 -0
- package/dist/types/src/components/FunctionEditor/index.d.ts +2 -0
- package/dist/types/src/components/FunctionEditor/index.d.ts.map +1 -0
- package/dist/types/src/components/GridSheet/GridSheet.d.ts +1 -8
- package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -1
- package/dist/types/src/components/{CellEditor/CellEditor.stories.d.ts → GridSheet/SheetCellEditor.stories.d.ts} +2 -2
- package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts.map +1 -0
- package/dist/types/src/components/GridSheet/index.d.ts +2 -0
- package/dist/types/src/components/GridSheet/index.d.ts.map +1 -0
- package/dist/types/src/components/GridSheet/util.d.ts +11 -2
- package/dist/types/src/components/GridSheet/util.d.ts.map +1 -1
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +6 -0
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -0
- package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts +11 -0
- package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -0
- package/dist/types/src/components/SheetContainer/index.d.ts +3 -0
- package/dist/types/src/components/SheetContainer/index.d.ts.map +1 -0
- package/dist/types/src/components/SheetContext/SheetContext.d.ts +27 -0
- package/dist/types/src/components/SheetContext/SheetContext.d.ts.map +1 -0
- package/dist/types/src/components/SheetContext/index.d.ts +2 -0
- package/dist/types/src/components/SheetContext/index.d.ts.map +1 -0
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +31 -17
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +1 -1
- package/dist/types/src/components/index.d.ts +3 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/extensions/editor/extension.d.ts.map +1 -0
- package/dist/types/src/extensions/editor/extension.test.d.ts.map +1 -0
- package/dist/types/src/extensions/editor/index.d.ts +2 -0
- package/dist/types/src/extensions/editor/index.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +1 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/threads.d.ts +8 -0
- package/dist/types/src/hooks/threads.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +3 -6
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/{components/Sheet → model}/decorations.d.ts +1 -0
- package/dist/types/src/model/decorations.d.ts.map +1 -0
- package/dist/types/src/model/formatting-model.d.ts +3 -0
- package/dist/types/src/model/formatting-model.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -0
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/sheet-model.d.ts +3 -2
- package/dist/types/src/model/sheet-model.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +13 -28
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +36 -39
- package/src/SheetPlugin.tsx +3 -2
- package/src/components/FunctionEditor/FunctionEditor.tsx +45 -0
- package/src/components/FunctionEditor/index.ts +5 -0
- package/src/components/GridSheet/GridSheet.stories.tsx +7 -2
- package/src/components/GridSheet/GridSheet.tsx +77 -69
- package/src/components/{CellEditor/CellEditor.stories.tsx → GridSheet/SheetCellEditor.stories.tsx} +2 -2
- package/src/components/{Sheet → GridSheet}/index.ts +1 -1
- package/src/components/GridSheet/util.ts +63 -27
- package/src/components/SheetContainer/SheetContainer.stories.tsx +40 -0
- package/src/components/SheetContainer/SheetContainer.tsx +52 -0
- package/src/components/SheetContainer/index.ts +7 -0
- package/src/components/{Sheet/sheet-context.tsx → SheetContext/SheetContext.tsx} +47 -27
- package/src/components/SheetContext/index.ts +5 -0
- package/src/components/Toolbar/Toolbar.tsx +127 -86
- package/src/components/index.ts +2 -1
- package/src/defs/util.ts +1 -1
- package/src/extensions/compute.stories.tsx +4 -4
- package/src/{components/CellEditor → extensions/editor}/index.ts +0 -1
- package/src/extensions/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/{components/Sheet/threads.tsx → hooks/threads.ts} +26 -84
- package/src/{meta.tsx → meta.ts} +3 -3
- package/src/{components/Sheet → model}/decorations.ts +2 -0
- package/src/model/formatting-model.ts +12 -9
- package/src/model/index.ts +1 -0
- package/src/model/sheet-model.test.ts +1 -3
- package/src/model/sheet-model.ts +13 -11
- package/src/types.ts +9 -35
- package/dist/lib/browser/SheetContainer-LG77O4RM.mjs +0 -262
- package/dist/lib/browser/SheetContainer-LG77O4RM.mjs.map +0 -7
- package/dist/lib/browser/chunk-CHQAW4F4.mjs +0 -2705
- package/dist/lib/browser/chunk-CHQAW4F4.mjs.map +0 -7
- package/dist/lib/browser/chunk-QILRZNE5.mjs.map +0 -7
- package/dist/lib/browser/chunk-WZMOZKQZ.mjs.map +0 -7
- package/dist/lib/node/SheetContainer-OZ7DHH4L.cjs +0 -280
- package/dist/lib/node/SheetContainer-OZ7DHH4L.cjs.map +0 -7
- package/dist/lib/node/chunk-5FTFZL5W.cjs +0 -2690
- package/dist/lib/node/chunk-5FTFZL5W.cjs.map +0 -7
- package/dist/lib/node/chunk-AOP42UAA.cjs.map +0 -7
- package/dist/lib/node/chunk-BNARJ5GM.cjs.map +0 -7
- package/dist/lib/node-esm/SheetContainer-4XS2G25Z.mjs +0 -263
- package/dist/lib/node-esm/SheetContainer-4XS2G25Z.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-IU2L277A.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-KK3XL37M.mjs +0 -2706
- package/dist/lib/node-esm/chunk-KK3XL37M.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RR2AO4SM.mjs.map +0 -7
- package/dist/types/src/components/CellEditor/CellEditor.d.ts +0 -34
- package/dist/types/src/components/CellEditor/CellEditor.d.ts.map +0 -1
- package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +0 -1
- package/dist/types/src/components/CellEditor/extension.d.ts.map +0 -1
- package/dist/types/src/components/CellEditor/extension.test.d.ts.map +0 -1
- package/dist/types/src/components/CellEditor/index.d.ts +0 -3
- package/dist/types/src/components/CellEditor/index.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/Sheet.d.ts +0 -55
- package/dist/types/src/components/Sheet/Sheet.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/Sheet.stories.d.ts +0 -53
- package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/decorations.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/grid.d.ts +0 -52
- package/dist/types/src/components/Sheet/grid.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/index.d.ts +0 -2
- package/dist/types/src/components/Sheet/index.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/nav.d.ts +0 -29
- package/dist/types/src/components/Sheet/nav.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/sheet-context.d.ts +0 -26
- package/dist/types/src/components/Sheet/sheet-context.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/threads.d.ts +0 -2
- package/dist/types/src/components/Sheet/threads.d.ts.map +0 -1
- package/dist/types/src/components/Sheet/util.d.ts +0 -18
- package/dist/types/src/components/Sheet/util.d.ts.map +0 -1
- package/dist/types/src/components/SheetContainer.d.ts +0 -8
- package/dist/types/src/components/SheetContainer.d.ts.map +0 -1
- package/dist/types/src/components/Toolbar/common.d.ts +0 -20
- package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
- package/src/components/CellEditor/CellEditor.tsx +0 -163
- package/src/components/Sheet/Sheet.stories.tsx +0 -251
- package/src/components/Sheet/Sheet.tsx +0 -1215
- package/src/components/Sheet/grid.ts +0 -191
- package/src/components/Sheet/nav.ts +0 -157
- package/src/components/Sheet/util.ts +0 -56
- package/src/components/SheetContainer.tsx +0 -86
- package/src/components/Toolbar/common.tsx +0 -72
- /package/dist/types/src/{components/CellEditor → extensions/editor}/extension.d.ts +0 -0
- /package/dist/types/src/{components/CellEditor → extensions/editor}/extension.test.d.ts +0 -0
- /package/src/{components/CellEditor → extensions/editor}/extension.test.ts +0 -0
- /package/src/{components/CellEditor → extensions/editor}/extension.ts +0 -0
|
@@ -2,48 +2,87 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
type Icon,
|
|
7
|
-
Calendar,
|
|
8
|
-
ChatText,
|
|
9
|
-
CurrencyDollar,
|
|
10
|
-
Eraser,
|
|
11
|
-
HighlighterCircle,
|
|
12
|
-
TextAlignCenter,
|
|
13
|
-
TextAlignLeft,
|
|
14
|
-
TextAlignRight,
|
|
15
|
-
} from '@phosphor-icons/react';
|
|
16
5
|
import { createContext } from '@radix-ui/react-context';
|
|
17
6
|
import React, { type PropsWithChildren } from 'react';
|
|
18
7
|
|
|
19
8
|
import {
|
|
20
|
-
|
|
21
|
-
ElevationProvider,
|
|
9
|
+
Icon,
|
|
22
10
|
Toolbar as NaturalToolbar,
|
|
23
|
-
type ThemedClassName,
|
|
24
11
|
useTranslation,
|
|
12
|
+
Tooltip,
|
|
13
|
+
type ToolbarToggleGroupItemProps as NaturalToolbarToggleGroupItemProps,
|
|
14
|
+
type ToolbarButtonProps as NaturalToolbarButtonProps,
|
|
15
|
+
type ToolbarToggleProps as NaturalToolbarToggleProps,
|
|
16
|
+
type ThemedClassName,
|
|
25
17
|
} from '@dxos/react-ui';
|
|
18
|
+
import { useAttention } from '@dxos/react-ui-attention';
|
|
26
19
|
import { nonNullable } from '@dxos/util';
|
|
27
20
|
|
|
28
|
-
import { ToolbarButton, ToolbarSeparator, ToolbarToggleButton } from './common';
|
|
29
21
|
import { addressToIndex } from '../../defs';
|
|
30
22
|
import { SHEET_PLUGIN } from '../../meta';
|
|
31
23
|
import { type Formatting } from '../../types';
|
|
32
|
-
import { useSheetContext } from '../
|
|
24
|
+
import { useSheetContext } from '../SheetContext';
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
// Buttons
|
|
28
|
+
//
|
|
29
|
+
|
|
30
|
+
const buttonStyles = 'min-bs-0 p-2';
|
|
31
|
+
const tooltipProps = { side: 'bottom' as const, classNames: 'z-10' };
|
|
32
|
+
|
|
33
|
+
const ToolbarSeparator = () => <div role='separator' className='grow' />;
|
|
34
|
+
|
|
35
|
+
//
|
|
36
|
+
// ToolbarItem
|
|
37
|
+
//
|
|
38
|
+
|
|
39
|
+
type ToolbarItemProps =
|
|
40
|
+
| (NaturalToolbarButtonProps & { itemType: 'button'; icon: string })
|
|
41
|
+
| (NaturalToolbarToggleGroupItemProps & { itemType: 'toggleGroupItem'; icon: string })
|
|
42
|
+
| (NaturalToolbarToggleProps & { itemType: 'toggle'; icon: string });
|
|
43
|
+
|
|
44
|
+
export const ToolbarItem = ({ itemType, icon, children, ...props }: ToolbarItemProps) => {
|
|
45
|
+
const Invoker =
|
|
46
|
+
itemType === 'toggleGroupItem'
|
|
47
|
+
? NaturalToolbar.ToggleGroupItem
|
|
48
|
+
: itemType === 'toggle'
|
|
49
|
+
? NaturalToolbar.Toggle
|
|
50
|
+
: NaturalToolbar.Button;
|
|
51
|
+
return (
|
|
52
|
+
<Tooltip.Root>
|
|
53
|
+
<Tooltip.Trigger asChild>
|
|
54
|
+
{/* TODO(thure): type the props spread better. */}
|
|
55
|
+
<Invoker variant='ghost' {...(props as any)} classNames={buttonStyles}>
|
|
56
|
+
<Icon icon={icon} size={5} />
|
|
57
|
+
<span className='sr-only'>{children}</span>
|
|
58
|
+
</Invoker>
|
|
59
|
+
</Tooltip.Trigger>
|
|
60
|
+
<Tooltip.Portal>
|
|
61
|
+
<Tooltip.Content {...tooltipProps}>
|
|
62
|
+
{children}
|
|
63
|
+
<Tooltip.Arrow />
|
|
64
|
+
</Tooltip.Content>
|
|
65
|
+
</Tooltip.Portal>
|
|
66
|
+
</Tooltip.Root>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
33
69
|
|
|
34
70
|
//
|
|
35
71
|
// Root
|
|
36
72
|
//
|
|
37
73
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
74
|
+
type AlignValue = 'left' | 'center' | 'right' | 'unset';
|
|
75
|
+
type AlignAction = { type: 'align'; value: AlignValue };
|
|
76
|
+
|
|
77
|
+
type CommentAction = { type: 'comment'; anchor: string; cellContent?: string };
|
|
78
|
+
|
|
79
|
+
type FormatValue = 'date' | 'currency' | 'unset';
|
|
80
|
+
type FormatAction = { type: 'format'; value: FormatValue };
|
|
81
|
+
|
|
82
|
+
type StyleValue = 'highlight' | 'unset';
|
|
83
|
+
type StyleAction = { type: 'style'; value: StyleValue };
|
|
84
|
+
|
|
85
|
+
export type ToolbarAction = StyleAction | AlignAction | FormatAction | CommentAction;
|
|
47
86
|
|
|
48
87
|
export type ToolbarActionType = ToolbarAction['type'];
|
|
49
88
|
|
|
@@ -52,30 +91,41 @@ export type ToolbarActionHandler = (action: ToolbarAction) => void;
|
|
|
52
91
|
export type ToolbarProps = ThemedClassName<
|
|
53
92
|
PropsWithChildren<{
|
|
54
93
|
onAction?: ToolbarActionHandler;
|
|
94
|
+
role?: string;
|
|
55
95
|
}>
|
|
56
96
|
>;
|
|
57
97
|
|
|
58
98
|
const [ToolbarContextProvider, useToolbarContext] = createContext<ToolbarProps>('Toolbar');
|
|
59
99
|
|
|
60
|
-
|
|
100
|
+
// TODO(Zan): Factor out, copied this from MarkdownPlugin.
|
|
101
|
+
const sectionToolbarLayout =
|
|
102
|
+
'bs-[--rail-action] bg-[--sticky-bg] sticky block-start-0 __-block-start-px transition-opacity';
|
|
103
|
+
|
|
104
|
+
const ToolbarRoot = ({ children, onAction, role, classNames }: ToolbarProps) => {
|
|
105
|
+
const { id } = useSheetContext();
|
|
106
|
+
const { hasAttention } = useAttention(id);
|
|
107
|
+
|
|
61
108
|
return (
|
|
62
109
|
<ToolbarContextProvider onAction={onAction}>
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
110
|
+
<NaturalToolbar.Root
|
|
111
|
+
classNames={[
|
|
112
|
+
...(role === 'section'
|
|
113
|
+
? ['z-[2] group-focus-within/section:visible', !hasAttention && 'invisible', sectionToolbarLayout]
|
|
114
|
+
: ['attention-surface']),
|
|
115
|
+
classNames,
|
|
116
|
+
]}
|
|
117
|
+
>
|
|
118
|
+
{children}
|
|
119
|
+
</NaturalToolbar.Root>
|
|
70
120
|
</ToolbarContextProvider>
|
|
71
121
|
);
|
|
72
122
|
};
|
|
73
123
|
|
|
74
124
|
// TODO(burdon): Generalize.
|
|
75
125
|
// TODO(burdon): Detect and display current state.
|
|
76
|
-
type ButtonProps = {
|
|
77
|
-
|
|
78
|
-
|
|
126
|
+
type ButtonProps<T> = {
|
|
127
|
+
value: T;
|
|
128
|
+
icon: string;
|
|
79
129
|
getState: (state: Formatting) => boolean;
|
|
80
130
|
disabled?: (state: Formatting) => boolean;
|
|
81
131
|
};
|
|
@@ -84,9 +134,9 @@ type ButtonProps = {
|
|
|
84
134
|
// Alignment
|
|
85
135
|
//
|
|
86
136
|
|
|
87
|
-
const formatOptions: ButtonProps[] = [
|
|
88
|
-
{
|
|
89
|
-
{
|
|
137
|
+
const formatOptions: ButtonProps<FormatValue>[] = [
|
|
138
|
+
{ value: 'date', icon: 'ph--calendar--regular', getState: (state) => false },
|
|
139
|
+
{ value: 'currency', icon: 'ph--currency-dollar--regular', getState: (state) => false },
|
|
90
140
|
];
|
|
91
141
|
|
|
92
142
|
const Format = () => {
|
|
@@ -98,26 +148,25 @@ const Format = () => {
|
|
|
98
148
|
type='single'
|
|
99
149
|
// value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
|
|
100
150
|
>
|
|
101
|
-
{formatOptions.map(({
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}
|
|
151
|
+
{formatOptions.map(({ value, getState, icon }) => (
|
|
152
|
+
<ToolbarItem
|
|
153
|
+
itemType='toggleGroupItem'
|
|
154
|
+
key={value}
|
|
155
|
+
value={value}
|
|
156
|
+
icon={icon}
|
|
157
|
+
onClick={() => onAction?.({ type: 'format', value })}
|
|
109
158
|
>
|
|
110
|
-
{t(`toolbar ${
|
|
111
|
-
</
|
|
159
|
+
{t(`toolbar ${value} label`)}
|
|
160
|
+
</ToolbarItem>
|
|
112
161
|
))}
|
|
113
162
|
</NaturalToolbar.ToggleGroup>
|
|
114
163
|
);
|
|
115
164
|
};
|
|
116
165
|
|
|
117
|
-
const alignmentOptions: ButtonProps[] = [
|
|
118
|
-
{
|
|
119
|
-
{
|
|
120
|
-
{
|
|
166
|
+
const alignmentOptions: ButtonProps<AlignValue>[] = [
|
|
167
|
+
{ value: 'left', icon: 'ph--text-align-left--regular', getState: (state) => false },
|
|
168
|
+
{ value: 'center', icon: 'ph--text-align-center--regular', getState: (state) => false },
|
|
169
|
+
{ value: 'right', icon: 'ph--text-align-right--regular', getState: (state) => false },
|
|
121
170
|
];
|
|
122
171
|
|
|
123
172
|
const Alignment = () => {
|
|
@@ -128,50 +177,41 @@ const Alignment = () => {
|
|
|
128
177
|
<NaturalToolbar.ToggleGroup
|
|
129
178
|
type='single'
|
|
130
179
|
// value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
|
|
180
|
+
// disabled={state?.blockType === 'codeblock'}
|
|
181
|
+
onValueChange={(value: AlignValue) => onAction?.({ type: 'align', value })}
|
|
131
182
|
>
|
|
132
|
-
{alignmentOptions.map(({
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Icon={Icon}
|
|
137
|
-
// disabled={state?.blockType === 'codeblock'}
|
|
138
|
-
// onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
|
|
139
|
-
onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}
|
|
140
|
-
>
|
|
141
|
-
{t(`toolbar ${type} label`)}
|
|
142
|
-
</ToolbarToggleButton>
|
|
183
|
+
{alignmentOptions.map(({ value, getState, icon }) => (
|
|
184
|
+
<ToolbarItem itemType='toggleGroupItem' key={value} value={value} icon={icon}>
|
|
185
|
+
{t(`toolbar ${value} label`)}
|
|
186
|
+
</ToolbarItem>
|
|
143
187
|
))}
|
|
144
188
|
</NaturalToolbar.ToggleGroup>
|
|
145
189
|
);
|
|
146
190
|
};
|
|
147
191
|
|
|
148
|
-
const styleOptions: ButtonProps[] = [
|
|
149
|
-
{
|
|
150
|
-
{ type: 'highlight', Icon: HighlighterCircle, getState: (state) => false },
|
|
192
|
+
const styleOptions: ButtonProps<StyleValue>[] = [
|
|
193
|
+
{ value: 'highlight', icon: 'ph--highlighter--regular', getState: (state) => false },
|
|
151
194
|
];
|
|
152
195
|
|
|
153
196
|
const Styles = () => {
|
|
154
|
-
const { onAction } = useToolbarContext('
|
|
197
|
+
const { onAction } = useToolbarContext('Styles');
|
|
155
198
|
const { t } = useTranslation(SHEET_PLUGIN);
|
|
156
199
|
|
|
157
200
|
return (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
// disabled={state?.blockType === 'codeblock'}
|
|
168
|
-
// onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
|
|
169
|
-
onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}
|
|
201
|
+
<>
|
|
202
|
+
{styleOptions.map(({ value, getState, icon }) => (
|
|
203
|
+
<ToolbarItem
|
|
204
|
+
itemType='toggle'
|
|
205
|
+
key={value}
|
|
206
|
+
onPressedChange={(nextPressed: boolean) =>
|
|
207
|
+
onAction?.({ type: 'style', value: nextPressed ? 'highlight' : 'unset' })
|
|
208
|
+
}
|
|
209
|
+
icon={icon}
|
|
170
210
|
>
|
|
171
|
-
{t(`toolbar ${
|
|
172
|
-
</
|
|
211
|
+
{t(`toolbar ${value} label`)}
|
|
212
|
+
</ToolbarItem>
|
|
173
213
|
))}
|
|
174
|
-
|
|
214
|
+
</>
|
|
175
215
|
);
|
|
176
216
|
};
|
|
177
217
|
|
|
@@ -206,9 +246,10 @@ const Actions = () => {
|
|
|
206
246
|
: 'comment label';
|
|
207
247
|
|
|
208
248
|
return (
|
|
209
|
-
<
|
|
249
|
+
<ToolbarItem
|
|
250
|
+
itemType='button'
|
|
210
251
|
value='comment'
|
|
211
|
-
|
|
252
|
+
icon='ph--chat-text--regular'
|
|
212
253
|
data-testid='editor.toolbar.comment'
|
|
213
254
|
onClick={() => {
|
|
214
255
|
if (!cursor) {
|
|
@@ -223,7 +264,7 @@ const Actions = () => {
|
|
|
223
264
|
disabled={!cursorOnly || overlapsCommentAnchor}
|
|
224
265
|
>
|
|
225
266
|
{t(tooltipLabelKey)}
|
|
226
|
-
</
|
|
267
|
+
</ToolbarItem>
|
|
227
268
|
);
|
|
228
269
|
};
|
|
229
270
|
|
package/src/components/index.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
|
|
7
7
|
export * from './ComputeGraph';
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './GridSheet';
|
|
9
|
+
export * from './SheetContext';
|
|
9
10
|
|
|
10
11
|
// Lazily load components for content surfaces.
|
|
11
12
|
export const SheetContainer = React.lazy(() => import('./SheetContainer'));
|
package/src/defs/util.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
|
21
21
|
import { nonNullable } from '@dxos/util';
|
|
22
22
|
|
|
23
23
|
import { compute, computeGraphFacet } from './compute';
|
|
24
|
-
import {
|
|
24
|
+
import { GridSheet, SheetProvider } from '../components';
|
|
25
25
|
import { useComputeGraph, useSheetModel } from '../hooks';
|
|
26
26
|
import { useTestSheet, withComputeGraphDecorator } from '../testing';
|
|
27
27
|
import { SheetType } from '../types';
|
|
@@ -80,9 +80,9 @@ const Grid = () => {
|
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
82
|
<div className='flex w-[40rem] overflow-hidden'>
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
</
|
|
83
|
+
<SheetProvider graph={graph} sheet={sheet}>
|
|
84
|
+
<GridSheet />
|
|
85
|
+
</SheetProvider>
|
|
86
86
|
</div>
|
|
87
87
|
);
|
|
88
88
|
};
|
package/src/extensions/index.ts
CHANGED
package/src/hooks/index.ts
CHANGED
|
@@ -3,82 +3,21 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { effect } from '@preact/signals-core';
|
|
6
|
-
import
|
|
6
|
+
import { type MutableRefObject, useCallback, useEffect, useMemo } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type IntentResolver, LayoutAction, useIntentDispatcher, useIntentResolver } from '@dxos/app-framework';
|
|
9
9
|
import { debounce } from '@dxos/async';
|
|
10
10
|
import { fullyQualifiedId } from '@dxos/react-client/echo';
|
|
11
|
-
import {
|
|
11
|
+
import { type DxGridElement, type DxGridPosition } from '@dxos/react-ui-grid';
|
|
12
12
|
|
|
13
|
-
import { type
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { SHEET_PLUGIN } from '../../meta';
|
|
17
|
-
|
|
18
|
-
// TODO(burdon): Move into folder; split hooks.
|
|
19
|
-
|
|
20
|
-
const CommentIndicator = () => {
|
|
21
|
-
return (
|
|
22
|
-
<div
|
|
23
|
-
role='none'
|
|
24
|
-
className='absolute top-0 right-0 w-0 h-0 border-t-8 border-l-8 border-t-cmCommentSurface border-l-transparent'
|
|
25
|
-
/>
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const ThreadedCellWrapper = ({ children }: PropsWithChildren) => {
|
|
30
|
-
const dispatch = useIntentDispatcher();
|
|
31
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
32
|
-
const { t } = useTranslation(SHEET_PLUGIN);
|
|
33
|
-
|
|
34
|
-
const handleClick = React.useCallback(
|
|
35
|
-
(_event: React.MouseEvent) => {
|
|
36
|
-
void dispatch({ action: LayoutAction.SET_LAYOUT, data: { element: 'complementary', state: true } });
|
|
37
|
-
},
|
|
38
|
-
[dispatch],
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div
|
|
43
|
-
role='none'
|
|
44
|
-
className='relative h-full is-full'
|
|
45
|
-
onMouseEnter={() => {
|
|
46
|
-
setIsHovered(true);
|
|
47
|
-
}}
|
|
48
|
-
onMouseLeave={() => {
|
|
49
|
-
setIsHovered(false);
|
|
50
|
-
}}
|
|
51
|
-
>
|
|
52
|
-
<CommentIndicator />
|
|
53
|
-
{isHovered && (
|
|
54
|
-
<div className='absolute inset-0 flex items-center justify-end pr-1'>
|
|
55
|
-
<button
|
|
56
|
-
className='ch-button text-xs min-bs-0 p-1'
|
|
57
|
-
onClick={handleClick}
|
|
58
|
-
aria-label={t('open comment for sheet cell')}
|
|
59
|
-
>
|
|
60
|
-
<Icon icon='ph--chat--regular' aria-hidden={true} />
|
|
61
|
-
</button>
|
|
62
|
-
</div>
|
|
63
|
-
)}
|
|
64
|
-
{children}
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const createThreadDecoration = (cellIndex: string, threadId: string, sheetId: string): Decoration => {
|
|
70
|
-
return {
|
|
71
|
-
type: 'comment',
|
|
72
|
-
cellIndex,
|
|
73
|
-
decorate: (props) => <ThreadedCellWrapper {...props} />,
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// TODO(burdon): Factor out hooks.
|
|
78
|
-
|
|
79
|
-
const useUpdateCursorOnThreadSelection = () => {
|
|
80
|
-
const { setCursor, model } = useSheetContext();
|
|
13
|
+
import { addressFromIndex, addressToIndex, type CellAddress, closest } from '../defs';
|
|
14
|
+
import { SHEET_PLUGIN } from '../meta';
|
|
15
|
+
import { type SheetModel, type Decoration, type Decorations } from '../model';
|
|
81
16
|
|
|
17
|
+
export const useUpdateFocusedCellOnThreadSelection = (
|
|
18
|
+
model: SheetModel,
|
|
19
|
+
grid: MutableRefObject<DxGridElement | null>,
|
|
20
|
+
) => {
|
|
82
21
|
const handleScrollIntoView: IntentResolver = useCallback(
|
|
83
22
|
({ action, data }) => {
|
|
84
23
|
switch (action) {
|
|
@@ -89,18 +28,17 @@ const useUpdateCursorOnThreadSelection = () => {
|
|
|
89
28
|
|
|
90
29
|
// TODO(Zan): Everywhere we refer to the cursor in a thread context should change to `anchor`.
|
|
91
30
|
const cellAddress = addressFromIndex(model.sheet, data.cursor);
|
|
92
|
-
|
|
31
|
+
grid.current?.setFocus({ ...cellAddress, plane: 'grid' }, true);
|
|
93
32
|
}
|
|
94
33
|
}
|
|
95
34
|
},
|
|
96
|
-
[model.sheet
|
|
35
|
+
[model.sheet],
|
|
97
36
|
);
|
|
98
37
|
|
|
99
38
|
useIntentResolver(SHEET_PLUGIN, handleScrollIntoView);
|
|
100
39
|
};
|
|
101
40
|
|
|
102
|
-
const
|
|
103
|
-
const { cursor, model } = useSheetContext();
|
|
41
|
+
export const useSelectThreadOnCellFocus = (model: SheetModel, cursor?: CellAddress) => {
|
|
104
42
|
const dispatch = useIntentDispatcher();
|
|
105
43
|
|
|
106
44
|
const activeThreads = useMemo(
|
|
@@ -108,7 +46,10 @@ const useSelectThreadOnCursorChange = () => {
|
|
|
108
46
|
model.sheet.threads?.filter(
|
|
109
47
|
(thread): thread is NonNullable<typeof thread> => !!thread && thread.status === 'active',
|
|
110
48
|
) ?? [],
|
|
111
|
-
[
|
|
49
|
+
[
|
|
50
|
+
// TODO(thure): Surely we can find a better dependency for this…
|
|
51
|
+
JSON.stringify(model.sheet.threads),
|
|
52
|
+
],
|
|
112
53
|
);
|
|
113
54
|
|
|
114
55
|
const activeThreadAddresses = useMemo(
|
|
@@ -143,7 +84,7 @@ const useSelectThreadOnCursorChange = () => {
|
|
|
143
84
|
);
|
|
144
85
|
|
|
145
86
|
const debounced = useMemo(() => {
|
|
146
|
-
return debounce((
|
|
87
|
+
return debounce((cellCoords: DxGridPosition) => requestAnimationFrame(() => selectClosestThread(cellCoords)), 50);
|
|
147
88
|
}, [selectClosestThread]);
|
|
148
89
|
|
|
149
90
|
useEffect(() => {
|
|
@@ -154,8 +95,15 @@ const useSelectThreadOnCursorChange = () => {
|
|
|
154
95
|
}, [cursor, selectClosestThread]);
|
|
155
96
|
};
|
|
156
97
|
|
|
157
|
-
const
|
|
158
|
-
|
|
98
|
+
const createThreadDecoration = (cellIndex: string, threadId: string, sheetId: string): Decoration => {
|
|
99
|
+
return {
|
|
100
|
+
type: 'comment',
|
|
101
|
+
classNames: ['bg-greenFill'],
|
|
102
|
+
cellIndex,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const useThreadDecorations = (model: SheetModel, decorations: Decorations) => {
|
|
159
107
|
const sheet = useMemo(() => model.sheet, [model.sheet]);
|
|
160
108
|
const sheetId = useMemo(() => fullyQualifiedId(sheet), [sheet]);
|
|
161
109
|
|
|
@@ -197,9 +145,3 @@ const useThreadDecorations = () => {
|
|
|
197
145
|
return () => unsubscribe();
|
|
198
146
|
});
|
|
199
147
|
};
|
|
200
|
-
|
|
201
|
-
export const useThreads = () => {
|
|
202
|
-
useUpdateCursorOnThreadSelection();
|
|
203
|
-
useSelectThreadOnCursorChange();
|
|
204
|
-
useThreadDecorations();
|
|
205
|
-
};
|
package/src/{meta.tsx → meta.ts}
RENAMED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type PluginMeta } from '@dxos/app-framework';
|
|
6
6
|
|
|
7
7
|
export const SHEET_PLUGIN = 'dxos.org/plugin/sheet';
|
|
8
8
|
|
|
9
|
-
export default
|
|
9
|
+
export default {
|
|
10
10
|
id: SHEET_PLUGIN,
|
|
11
11
|
name: 'Sheet',
|
|
12
12
|
description: 'A simple spreadsheet plugin.',
|
|
13
13
|
icon: 'ph--grid-nine--regular',
|
|
14
|
-
}
|
|
14
|
+
} satisfies PluginMeta;
|
|
@@ -3,17 +3,20 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type ClassNameValue } from '@dxos/react-ui-types';
|
|
6
|
+
import { FieldValueType } from '@dxos/schema';
|
|
6
7
|
|
|
7
8
|
import { type SheetModel } from './sheet-model';
|
|
8
9
|
import { type CellAddress, inRange } from '../defs';
|
|
9
10
|
import { addressToIndex, rangeFromIndex } from '../defs';
|
|
10
|
-
import { ValueTypeEnum } from '../types';
|
|
11
11
|
|
|
12
12
|
export type CellFormat = {
|
|
13
13
|
value?: string;
|
|
14
14
|
classNames?: ClassNameValue;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated See react-ui-data.
|
|
19
|
+
*/
|
|
17
20
|
export class FormattingModel {
|
|
18
21
|
constructor(private readonly _model: SheetModel) {}
|
|
19
22
|
|
|
@@ -31,7 +34,7 @@ export class FormattingModel {
|
|
|
31
34
|
|
|
32
35
|
// Cell-specific formatting.
|
|
33
36
|
const idx = addressToIndex(this._model.sheet, cell);
|
|
34
|
-
let formatting = this._model.sheet.formatting?.
|
|
37
|
+
let formatting = this._model.sheet.formatting.find?.(({ range }) => range === idx);
|
|
35
38
|
const classNames = [...(formatting?.classNames ?? [])];
|
|
36
39
|
|
|
37
40
|
// Range formatting.
|
|
@@ -55,7 +58,7 @@ export class FormattingModel {
|
|
|
55
58
|
|
|
56
59
|
const type = formatting?.type ?? this._model.getValueType(cell);
|
|
57
60
|
switch (type) {
|
|
58
|
-
case
|
|
61
|
+
case FieldValueType.Boolean: {
|
|
59
62
|
return {
|
|
60
63
|
value: (value as boolean).toLocaleString().toUpperCase(),
|
|
61
64
|
classNames: [...classNames, value ? '!text-greenText' : '!text-orangeText'],
|
|
@@ -66,15 +69,15 @@ export class FormattingModel {
|
|
|
66
69
|
// Numbers.
|
|
67
70
|
//
|
|
68
71
|
|
|
69
|
-
case
|
|
72
|
+
case FieldValueType.Number: {
|
|
70
73
|
return { value: value.toLocaleString(locales), classNames: [...classNames, defaultNumber] };
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
case
|
|
76
|
+
case FieldValueType.Percent: {
|
|
74
77
|
return { value: (value as number) * 100 + '%', classNames: [...classNames, defaultNumber] };
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
case
|
|
80
|
+
case FieldValueType.Currency: {
|
|
78
81
|
return {
|
|
79
82
|
value: (value as number).toLocaleString(locales, {
|
|
80
83
|
style: 'currency',
|
|
@@ -90,17 +93,17 @@ export class FormattingModel {
|
|
|
90
93
|
// Dates.
|
|
91
94
|
//
|
|
92
95
|
|
|
93
|
-
case
|
|
96
|
+
case FieldValueType.DateTime: {
|
|
94
97
|
const date = this._model.toLocalDate(value as number);
|
|
95
98
|
return { value: date.toLocaleString(locales), classNames };
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
case
|
|
101
|
+
case FieldValueType.Date: {
|
|
99
102
|
const date = this._model.toLocalDate(value as number);
|
|
100
103
|
return { value: date.toLocaleDateString(locales), classNames };
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
case
|
|
106
|
+
case FieldValueType.Time: {
|
|
104
107
|
const date = this._model.toLocalDate(value as number);
|
|
105
108
|
return { value: date.toLocaleTimeString(locales), classNames };
|
|
106
109
|
}
|
package/src/model/index.ts
CHANGED
|
@@ -8,12 +8,10 @@ import { Trigger } from '@dxos/async';
|
|
|
8
8
|
import { FunctionType } from '@dxos/plugin-script/types';
|
|
9
9
|
|
|
10
10
|
import { SheetModel } from './sheet-model';
|
|
11
|
-
import {
|
|
11
|
+
import { addressFromA1Notation, createSheet } from '../defs';
|
|
12
12
|
import { TestBuilder, testFunctionPlugins } from '../graph/testing';
|
|
13
13
|
import { type CellScalarValue } from '../types';
|
|
14
14
|
|
|
15
|
-
// TODO(burdon): GPT("prompt", inputs); e.g., with large text cells.
|
|
16
|
-
|
|
17
15
|
describe('SheetModel', () => {
|
|
18
16
|
let testBuilder: TestBuilder;
|
|
19
17
|
beforeEach(async () => {
|