Skip to content

Commit 15e2db4

Browse files
committed
Fix document errors & Add image float support #741
1 parent 34724ee commit 15e2db4

30 files changed

+3167
-2541
lines changed

browser/data-browser/package.json

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,97 +5,98 @@
55
"name": "Joep Meindertsma"
66
},
77
"dependencies": {
8-
"@ai-sdk/react": "^2.0.29",
8+
"@ai-sdk/react": "^2.0.101",
99
"@bugsnag/core": "^7.25.0",
1010
"@bugsnag/js": "^7.25.0",
1111
"@bugsnag/plugin-react": "^7.25.0",
1212
"@codemirror/lang-json": "^6.0.2",
13-
"@codemirror/lint": "^6.8.5",
14-
"@dagrejs/dagre": "^1.1.4",
15-
"@dnd-kit/core": "^6.1.0",
13+
"@codemirror/lint": "^6.9.2",
14+
"@dagrejs/dagre": "^1.1.8",
15+
"@dnd-kit/core": "^6.3.1",
1616
"@dnd-kit/sortable": "^8.0.0",
1717
"@dnd-kit/utilities": "^3.2.2",
1818
"@emoji-mart/react": "^1.1.1",
1919
"@emotion/is-prop-valid": "^1.4.0",
2020
"@floating-ui/dom": "^1.7.4",
21-
"@modelcontextprotocol/sdk": "^1.13.3",
21+
"@modelcontextprotocol/sdk": "^1.22.0",
2222
"@oddbird/css-anchor-positioning": "^0.6.1",
23-
"@openrouter/ai-sdk-provider": "^1.2.0",
23+
"@openrouter/ai-sdk-provider": "^1.2.5",
2424
"@radix-ui/react-popover": "^1.1.15",
25-
"@radix-ui/react-scroll-area": "^1.2.0",
26-
"@radix-ui/react-tabs": "^1.1.1",
27-
"@tanstack/react-router": "^1.95.1",
28-
"@tiptap/core": "^3.7.2",
29-
"@tiptap/extension-collaboration": "^3.7.2",
30-
"@tiptap/extension-collaboration-caret": "^3.7.2",
31-
"@tiptap/extension-drag-handle-react": "^3.7.2",
32-
"@tiptap/extension-file-handler": "^3.7.2",
33-
"@tiptap/extension-image": "^3.7.2",
34-
"@tiptap/extension-link": "^3.7.2",
35-
"@tiptap/extension-list": "^3.7.2",
36-
"@tiptap/extension-mention": "^3.7.2",
37-
"@tiptap/extension-placeholder": "^3.7.2",
38-
"@tiptap/extension-table": "^3.10.5",
39-
"@tiptap/extension-text-align": "^3.7.2",
40-
"@tiptap/extension-text-style": "^3.7.2",
41-
"@tiptap/extension-typography": "^3.7.2",
42-
"@tiptap/markdown": "^3.7.2",
43-
"@tiptap/pm": "^3.7.2",
44-
"@tiptap/react": "^3.7.2",
45-
"@tiptap/starter-kit": "^3.7.2",
46-
"@tiptap/suggestion": "^3.7.2",
47-
"@tiptap/y-tiptap": "^3.0.0",
25+
"@radix-ui/react-scroll-area": "^1.2.10",
26+
"@radix-ui/react-tabs": "^1.1.13",
27+
"@tanstack/react-router": "^1.139.3",
28+
"@tiptap/core": "^3.11.0",
29+
"@tiptap/extension-collaboration": "^3.11.0",
30+
"@tiptap/extension-collaboration-caret": "^3.11.0",
31+
"@tiptap/extension-drag-handle": "^3.11.0",
32+
"@tiptap/extension-drag-handle-react": "^3.11.0",
33+
"@tiptap/extension-file-handler": "^3.11.0",
34+
"@tiptap/extension-image": "^3.11.0",
35+
"@tiptap/extension-link": "^3.11.0",
36+
"@tiptap/extension-list": "^3.11.0",
37+
"@tiptap/extension-mention": "^3.11.0",
38+
"@tiptap/extension-node-range": "^3.11.0",
39+
"@tiptap/extension-placeholder": "^3.11.0",
40+
"@tiptap/extension-table": "^3.11.0",
41+
"@tiptap/extension-text-align": "^3.11.0",
42+
"@tiptap/extension-text-style": "^3.11.0",
43+
"@tiptap/extension-typography": "^3.11.0",
44+
"@tiptap/markdown": "^3.11.0",
45+
"@tiptap/pm": "^3.11.0",
46+
"@tiptap/react": "^3.11.0",
47+
"@tiptap/starter-kit": "^3.11.0",
48+
"@tiptap/suggestion": "^3.11.0",
49+
"@tiptap/y-tiptap": "^3.0.1",
4850
"@tomic/react": "workspace:*",
49-
"@uiw/codemirror-theme-github": "^4.24.1",
50-
"@uiw/react-codemirror": "^4.24.1",
51-
"@wuchale/jsx": "^0.9.4",
51+
"@uiw/codemirror-theme-github": "^4.25.3",
52+
"@uiw/react-codemirror": "^4.25.3",
53+
"@wuchale/jsx": "^0.9.5",
5254
"@wuchale/vite-plugin": "^0.15.3",
53-
"ai": "^5.0.29",
55+
"ai": "^5.0.101",
5456
"clsx": "^2.1.1",
55-
"downshift": "^9.0.9",
57+
"downshift": "^9.0.10",
5658
"emoji-mart": "^5.6.0",
57-
"ollama-ai-provider-v2": "^1.3.1",
59+
"ollama-ai-provider-v2": "^1.5.5",
5860
"polished": "^4.3.1",
59-
"prismjs": "^1.29.0",
61+
"prismjs": "^1.30.0",
6062
"quick-score": "^0.2.0",
6163
"react": "^19.2.0",
6264
"react-colorful": "^5.6.1",
6365
"react-dom": "^19.2.0",
6466
"react-dropzone": "^11.7.1",
65-
"react-hot-toast": "^2.4.1",
67+
"react-hot-toast": "^2.6.0",
6668
"react-hotkeys-hook": "^3.4.7",
6769
"react-icons": "^4.12.0",
68-
"react-intersection-observer": "^9.13.1",
70+
"react-intersection-observer": "^9.16.0",
6971
"react-is": "^19.2.0",
70-
"react-markdown": "^9.0.3",
72+
"react-markdown": "^9.1.0",
7173
"react-pdf": "^10.2.0",
72-
"react-virtualized-auto-sizer": "^1.0.24",
73-
"react-window": "^1.8.10",
74+
"react-virtualized-auto-sizer": "^1.0.26",
75+
"react-window": "^1.8.11",
7476
"reactflow": "^11.11.4",
75-
"remark-gfm": "^4.0.0",
77+
"remark-gfm": "^4.0.1",
7678
"styled-components": "^6.1.19",
7779
"stylis": "4.3.0",
78-
"tiptap-markdown": "^0.8.10",
79-
"wuchale": "^0.18.3",
80+
"wuchale": "^0.18.5",
8081
"y-protocols": "^1.0.6",
8182
"yjs": "^13.6.27",
82-
"zod": "^4.1.5"
83+
"zod": "^4.1.13"
8384
},
8485
"devDependencies": {
85-
"@tanstack/router-devtools": "^1.95.1",
86+
"@tanstack/router-devtools": "^1.139.3",
8687
"@types/prismjs": "^1.26.5",
87-
"@types/react": "^19.2.2",
88-
"@types/react-dom": "^19.2.2",
88+
"@types/react": "^19.2.6",
89+
"@types/react-dom": "^19.2.3",
8990
"@types/react-window": "^1.8.8",
90-
"@vitejs/plugin-react": "^5.0.4",
91+
"@vitejs/plugin-react": "^5.1.1",
9192
"babel-plugin-react-compiler": "1.0.0",
9293
"babel-plugin-styled-components": "^2.1.4",
93-
"csstype": "^3.1.3",
94+
"csstype": "^3.2.3",
9495
"gh-pages": "^5.0.0",
9596
"lint-staged": "^10.5.4",
9697
"types-wm": "^1.1.0",
9798
"typescript": "^5.9.3",
98-
"vite": "^7.1.12",
99+
"vite": "^7.2.4",
99100
"vite-plugin-prismjs": "^0.0.11",
100101
"vite-plugin-pwa": "^1.1.0",
101102
"vite-plugin-webfont-dl": "^3.11.1"

browser/data-browser/src/chunks/RTE/AIChatInput/AsyncAIChatInput.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { EditorWrapperBase } from '../EditorWrapperBase';
88
import { searchSuggestionBuilder } from './mcpSuggestions';
99
import { useRef, useState } from 'react';
1010
import { EditorEvents } from '../EditorEvents';
11-
import { Markdown } from 'tiptap-markdown';
11+
import { Markdown } from '@tiptap/markdown';
1212
import { useStore } from '@tomic/react';
1313
import { useSettings } from '../../../helpers/AppSettings';
1414
import type { Node } from '@tiptap/pm/model';
@@ -108,7 +108,9 @@ const AsyncAIChatInput: React.FC<
108108
{
109109
extensions: [
110110
Markdown.configure({
111-
html: true,
111+
markedOptions: {
112+
gfm: true,
113+
},
112114
}),
113115
StarterKit.extend({
114116
addKeyboardShortcuts() {
@@ -174,14 +176,14 @@ const AsyncAIChatInput: React.FC<
174176
),
175177
],
176178
autofocus: true,
179+
contentType: 'markdown',
177180
editable: !disabled,
178181
},
179182
[serversWithResources, searchResourcesOfServer, disabled],
180183
);
181184

182185
const handleChange = () => {
183-
// @ts-expect-error - markdown is a valid storage
184-
const value = editor.storage.markdown.getMarkdown();
186+
const value = editor.getMarkdown();
185187
setMarkdown(value);
186188
markdownRef.current = value;
187189
onChange(value);

browser/data-browser/src/chunks/RTE/AsyncMarkdownEditor.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { EditorContent, useEditor } from '@tiptap/react';
2-
import { FloatingMenu } from '@tiptap/react/menus';
32
import { StarterKit } from '@tiptap/starter-kit';
43
import { Link } from '@tiptap/extension-link';
54
import { Placeholder } from '@tiptap/extension-placeholder';
@@ -17,10 +16,10 @@ import { usePopoverContainer } from '../../components/Popover';
1716
import {
1817
StyledEditorWrapper,
1918
RawEditor,
20-
FloatingMenuText,
2119
FloatingCodeButton,
2220
} from './sharedEditorStyles';
2321
import { TaskItem, TaskList } from '@tiptap/extension-list';
22+
import { FloatingHint } from './FloatingHint';
2423

2524
export type AsyncMarkdownEditorProps = {
2625
placeholder?: string;
@@ -82,6 +81,7 @@ export default function AsyncMarkdownEditor({
8281
HTMLAttributes: {
8382
class: 'tiptap-image',
8483
},
84+
markdownCompatible: true,
8585
}),
8686
Placeholder.configure({
8787
placeholder: placeholder ?? 'Start typing...',
@@ -143,9 +143,9 @@ export default function AsyncMarkdownEditor({
143143
/>
144144
)}
145145
<EditorContent key='rich-editor' editor={editor}>
146-
<FloatingMenu editor={editor ?? null}>
147-
<FloatingMenuText>Type &apos;/&apos; for options</FloatingMenuText>
148-
</FloatingMenu>
146+
<FloatingHint editor={editor}>
147+
Type &apos;/&apos; for options
148+
</FloatingHint>
149149
<BubbleMenu />
150150
<EditorEvents onChange={handleChange} />
151151
</EditorContent>

browser/data-browser/src/chunks/RTE/CollaborativeEditor.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { EditorContent, useEditor, type Editor } from '@tiptap/react';
2-
import { FloatingMenu } from '@tiptap/react/menus';
32
import { StarterKit } from '@tiptap/starter-kit';
43
import { Link } from '@tiptap/extension-link';
54
import { Placeholder } from '@tiptap/extension-placeholder';
@@ -22,7 +21,6 @@ import {
2221
buildResourceSuggestion,
2322
} from './ResourceExtension/ResourceExtention';
2423
import { ExtendedImage } from './ImagePicker';
25-
import { FloatingMenuText } from './sharedEditorStyles';
2624
import * as Y from 'yjs';
2725
import {
2826
dataBrowser,
@@ -38,7 +36,7 @@ import { EditorEvents } from './EditorEvents';
3836
import { useYSync } from './useYSync';
3937
import { randomItem } from '@helpers/randomItem';
4038
import { EditorWrapperBase } from './EditorWrapperBase';
41-
import styled from 'styled-components';
39+
import styled, { useTheme } from 'styled-components';
4240
import { useSettings } from '@helpers/AppSettings';
4341
import { FullBubbleMenu } from './FullBubbleMenu';
4442
import {
@@ -57,6 +55,9 @@ import toast from 'react-hot-toast';
5755
import { Row } from '@components/Row';
5856
import { Button } from '@components/Button';
5957
import { Note } from './NoteExtention/NoteExtention';
58+
import { FloatingHint } from './FloatingHint';
59+
import { TableKit } from '@tiptap/extension-table';
60+
import { useCustomBodyColor } from '@hooks/useCustomBodyColor';
6061

6162
export type CollaborativeEditorProps = {
6263
placeholder?: string;
@@ -87,6 +88,9 @@ export default function CollaborativeEditor({
8788
const awareness = useYSync(resource, property, doc);
8889
const canWrite = useCanWrite(resource);
8990

91+
const theme = useTheme();
92+
useCustomBodyColor(theme.colors.bg);
93+
9094
const uploadAndInsertImage = async (
9195
currentEditor: Editor,
9296
files: File[],
@@ -110,6 +114,9 @@ export default function CollaborativeEditor({
110114
StarterKit.configure({
111115
undoRedo: false,
112116
link: false,
117+
codeBlock: {
118+
enableTabIndentation: true,
119+
},
113120
}),
114121
Note,
115122
Typography,
@@ -238,6 +245,7 @@ export default function CollaborativeEditor({
238245
nested: true,
239246
}),
240247
TextStyle,
248+
TableKit,
241249
Color,
242250
BackgroundColor,
243251
FileHandler.configure({
@@ -318,11 +326,9 @@ export default function CollaborativeEditor({
318326
<FaGripVertical />
319327
</DragHandle>
320328
<EditorContent key='rich-editor' editor={editor}>
321-
<FloatingMenu editor={editor}>
322-
<FloatingMenuText>
323-
Type &apos;/&apos; for options or &apos;@&apos; for resources
324-
</FloatingMenuText>
325-
</FloatingMenu>
329+
<FloatingHint editor={editor}>
330+
Type &apos;/&apos; for options or &apos;@&apos; for resources
331+
</FloatingHint>
326332
<FullBubbleMenu />
327333
<EditorEvents onChange={save} />
328334
</EditorContent>

browser/data-browser/src/chunks/RTE/ColorMenu.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,31 @@ const defaultBackgroundColors = defaultColors.map(color =>
2828
// Add a good highlight color to the first position.
2929
defaultBackgroundColors[0] = '#e9ff70';
3030

31+
const sanitizeColor = (color: string | undefined) => {
32+
if (color === undefined) return;
33+
34+
// Word sometimes adds `!important` to the color, which breaks the color picker.
35+
return color.replace('!important', '').trim();
36+
};
37+
3138
export const ColorMenu: React.FC = () => {
3239
const editor = useTipTapEditor();
3340
const { selectedTextColor, selectedBackgroundColor } = useEditorState({
3441
editor,
3542
selector: snapshot => {
3643
return {
37-
selectedTextColor:
44+
selectedTextColor: sanitizeColor(
3845
(snapshot.editor.getAttributes('textStyle').color as
3946
| string
4047
| undefined
4148
| null) || undefined,
42-
selectedBackgroundColor:
49+
),
50+
selectedBackgroundColor: sanitizeColor(
4351
(snapshot.editor.getAttributes('textStyle').backgroundColor as
4452
| string
4553
| undefined
4654
| null) || undefined,
55+
),
4756
};
4857
},
4958
});

browser/data-browser/src/chunks/RTE/EditorWrapperBase.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,13 @@ export const EditorWrapperBase = styled.div<{ hideEditor: boolean }>`
117117
margin: 0;
118118
}
119119
}
120+
table {
121+
border-collapse: collapse;
122+
td,
123+
th {
124+
border: 1px solid ${p => p.theme.colors.bg2};
125+
padding: ${p => p.theme.size(2)};
126+
}
127+
}
120128
}
121129
`;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { Editor } from '@tiptap/core';
2+
import { FloatingMenu } from '@tiptap/react/menus';
3+
import { styled } from 'styled-components';
4+
5+
interface FloatingHintProps {
6+
editor: Editor;
7+
}
8+
9+
export const FloatingHint: React.FC<
10+
React.PropsWithChildren<FloatingHintProps>
11+
> = ({ editor, children }) => {
12+
const floatingMenuRef = (node: HTMLDivElement) => {
13+
if (node) {
14+
node.tabIndex = -1;
15+
16+
const observer = new MutationObserver(mutations => {
17+
for (const mutation of mutations) {
18+
if (
19+
mutation.type === 'attributes' &&
20+
node.getAttribute('tabindex') !== '-1'
21+
) {
22+
node.setAttribute('tabindex', '-1');
23+
}
24+
}
25+
});
26+
27+
observer.observe(node, {
28+
attributes: true,
29+
attributeFilter: ['tabindex'],
30+
});
31+
32+
return () => observer.disconnect();
33+
}
34+
};
35+
36+
return (
37+
<FloatingMenu editor={editor} ref={floatingMenuRef}>
38+
<FloatingMenuText>{children}</FloatingMenuText>
39+
</FloatingMenu>
40+
);
41+
};
42+
43+
export const FloatingMenuText = styled.span`
44+
color: ${p => p.theme.colors.textLight};
45+
user-select: none;
46+
`;

0 commit comments

Comments
 (0)