@pilotiq/tiptap 3.10.5 → 3.10.7

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.
Files changed (135) hide show
  1. package/CHANGELOG.md +751 -0
  2. package/boost/guidelines.md +268 -0
  3. package/boost/skills/pilotiq-tiptap-blocks/SKILL.md +48 -0
  4. package/boost/skills/pilotiq-tiptap-blocks/rules/custom-blocks.md +90 -0
  5. package/boost/skills/pilotiq-tiptap-blocks/rules/slash-menu-and-mentions.md +101 -0
  6. package/boost/skills/pilotiq-tiptap-blocks/rules/toolbar-and-extensibility.md +161 -0
  7. package/dist/markdownExtension.js +259 -164
  8. package/dist/react/BlockNodeView.d.ts +1 -1
  9. package/dist/react/FloatingToolbar.d.ts +1 -1
  10. package/dist/react/MentionMenu.d.ts +1 -1
  11. package/dist/react/Palette.d.ts +1 -1
  12. package/dist/react/SlashMenu.d.ts +1 -1
  13. package/dist/react/TableFloatingToolbar.d.ts +1 -1
  14. package/dist/react/TiptapEditor.d.ts +1 -1
  15. package/dist/react/Toolbar.d.ts +2 -2
  16. package/package.json +6 -4
  17. package/dist/Block.d.ts.map +0 -1
  18. package/dist/Block.js.map +0 -1
  19. package/dist/MentionProvider.d.ts.map +0 -1
  20. package/dist/MentionProvider.js.map +0 -1
  21. package/dist/PlainTextEditor.d.ts.map +0 -1
  22. package/dist/PlainTextEditor.js.map +0 -1
  23. package/dist/RichTextField.d.ts.map +0 -1
  24. package/dist/RichTextField.js.map +0 -1
  25. package/dist/extensions/AiInlineDiffExtension.d.ts.map +0 -1
  26. package/dist/extensions/AiInlineDiffExtension.js.map +0 -1
  27. package/dist/extensions/AiSuggestionExtension.d.ts.map +0 -1
  28. package/dist/extensions/AiSuggestionExtension.js.map +0 -1
  29. package/dist/extensions/BlockNodeExtension.d.ts.map +0 -1
  30. package/dist/extensions/BlockNodeExtension.js.map +0 -1
  31. package/dist/extensions/DragHandleExtension.d.ts.map +0 -1
  32. package/dist/extensions/DragHandleExtension.js.map +0 -1
  33. package/dist/extensions/GridExtension.d.ts.map +0 -1
  34. package/dist/extensions/GridExtension.js.map +0 -1
  35. package/dist/extensions/MentionExtension.d.ts.map +0 -1
  36. package/dist/extensions/MentionExtension.js.map +0 -1
  37. package/dist/extensions/MergeTagExtension.d.ts.map +0 -1
  38. package/dist/extensions/MergeTagExtension.js.map +0 -1
  39. package/dist/extensions/SlashCommandExtension.d.ts.map +0 -1
  40. package/dist/extensions/SlashCommandExtension.js.map +0 -1
  41. package/dist/extensions/TextSizeMarks.d.ts.map +0 -1
  42. package/dist/extensions/TextSizeMarks.js.map +0 -1
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/index.js.map +0 -1
  45. package/dist/markdownExtension.d.ts.map +0 -1
  46. package/dist/markdownStorage.d.ts.map +0 -1
  47. package/dist/markdownStorage.js.map +0 -1
  48. package/dist/plugin.d.ts.map +0 -1
  49. package/dist/plugin.js.map +0 -1
  50. package/dist/react/AiSuggestionBanner.d.ts.map +0 -1
  51. package/dist/react/AiSuggestionBanner.js.map +0 -1
  52. package/dist/react/BlockNodeView.d.ts.map +0 -1
  53. package/dist/react/BlockNodeView.js.map +0 -1
  54. package/dist/react/BlockSidePanel.d.ts.map +0 -1
  55. package/dist/react/BlockSidePanel.js.map +0 -1
  56. package/dist/react/CollabTextRenderer.d.ts.map +0 -1
  57. package/dist/react/CollabTextRenderer.js.map +0 -1
  58. package/dist/react/FloatingToolbar.d.ts.map +0 -1
  59. package/dist/react/FloatingToolbar.js.map +0 -1
  60. package/dist/react/MarkdownEditor.d.ts.map +0 -1
  61. package/dist/react/MarkdownEditor.js.map +0 -1
  62. package/dist/react/MentionMenu.d.ts.map +0 -1
  63. package/dist/react/MentionMenu.js.map +0 -1
  64. package/dist/react/Palette.d.ts.map +0 -1
  65. package/dist/react/Palette.js.map +0 -1
  66. package/dist/react/SlashMenu.d.ts.map +0 -1
  67. package/dist/react/SlashMenu.js.map +0 -1
  68. package/dist/react/TableFloatingToolbar.d.ts.map +0 -1
  69. package/dist/react/TableFloatingToolbar.js.map +0 -1
  70. package/dist/react/TiptapEditor.d.ts.map +0 -1
  71. package/dist/react/TiptapEditor.js.map +0 -1
  72. package/dist/react/Toolbar.d.ts.map +0 -1
  73. package/dist/react/Toolbar.js.map +0 -1
  74. package/dist/react/toolbarButtons.d.ts.map +0 -1
  75. package/dist/react/toolbarButtons.js.map +0 -1
  76. package/dist/react/useAiInlineDiff.d.ts.map +0 -1
  77. package/dist/react/useAiInlineDiff.js.map +0 -1
  78. package/dist/react/useAiSuggestionBridge.d.ts.map +0 -1
  79. package/dist/react/useAiSuggestionBridge.js.map +0 -1
  80. package/dist/register.d.ts.map +0 -1
  81. package/dist/register.js.map +0 -1
  82. package/dist/render.d.ts.map +0 -1
  83. package/dist/render.js.map +0 -1
  84. package/dist/surgicalOps.d.ts.map +0 -1
  85. package/dist/surgicalOps.js.map +0 -1
  86. package/dist/test/setup.d.ts.map +0 -1
  87. package/dist/test/setup.js.map +0 -1
  88. package/src/Block.ts +0 -75
  89. package/src/MentionProvider.ts +0 -153
  90. package/src/PlainTextEditor.dom.test.ts +0 -111
  91. package/src/PlainTextEditor.test.ts +0 -158
  92. package/src/PlainTextEditor.ts +0 -229
  93. package/src/RichTextField.test.ts +0 -447
  94. package/src/RichTextField.ts +0 -508
  95. package/src/extensions/AiInlineDiffExtension.ts +0 -286
  96. package/src/extensions/AiSuggestionExtension.test.ts +0 -141
  97. package/src/extensions/AiSuggestionExtension.ts +0 -522
  98. package/src/extensions/BlockNodeExtension.ts +0 -134
  99. package/src/extensions/DragHandleExtension.ts +0 -184
  100. package/src/extensions/GridExtension.test.ts +0 -31
  101. package/src/extensions/GridExtension.ts +0 -138
  102. package/src/extensions/MentionExtension.ts +0 -248
  103. package/src/extensions/MergeTagExtension.ts +0 -75
  104. package/src/extensions/SlashCommandExtension.test.ts +0 -147
  105. package/src/extensions/SlashCommandExtension.ts +0 -332
  106. package/src/extensions/TextSizeMarks.ts +0 -73
  107. package/src/index.ts +0 -62
  108. package/src/markdownExtension.ts +0 -19
  109. package/src/markdownStorage.ts +0 -49
  110. package/src/plugin.test.ts +0 -19
  111. package/src/plugin.ts +0 -26
  112. package/src/react/AiSuggestionBanner.tsx +0 -185
  113. package/src/react/BlockNodeView.tsx +0 -99
  114. package/src/react/BlockSidePanel.dom.test.tsx +0 -38
  115. package/src/react/BlockSidePanel.test.ts +0 -412
  116. package/src/react/BlockSidePanel.tsx +0 -451
  117. package/src/react/CollabTextRenderer.tsx +0 -228
  118. package/src/react/FloatingToolbar.tsx +0 -304
  119. package/src/react/MarkdownEditor.tsx +0 -603
  120. package/src/react/MentionMenu.tsx +0 -120
  121. package/src/react/Palette.tsx +0 -86
  122. package/src/react/SlashMenu.tsx +0 -129
  123. package/src/react/TableFloatingToolbar.tsx +0 -154
  124. package/src/react/TiptapEditor.dom.test.tsx +0 -112
  125. package/src/react/TiptapEditor.tsx +0 -777
  126. package/src/react/Toolbar.tsx +0 -438
  127. package/src/react/toolbarButtons.tsx +0 -579
  128. package/src/react/useAiInlineDiff.ts +0 -342
  129. package/src/react/useAiSuggestionBridge.ts +0 -223
  130. package/src/register.test.ts +0 -14
  131. package/src/register.ts +0 -42
  132. package/src/render.test.ts +0 -745
  133. package/src/render.ts +0 -480
  134. package/src/surgicalOps.ts +0 -205
  135. package/src/test/setup.ts +0 -64
@@ -1,304 +0,0 @@
1
- import { useEffect, useState, type ReactNode } from 'react'
2
- import type { Editor } from '@tiptap/core'
3
- import { Tooltip } from '@base-ui/react/tooltip'
4
- import { Dialog } from '@base-ui/react/dialog'
5
-
6
- interface FloatingToolbarProps {
7
- editor: Editor
8
- }
9
-
10
- /**
11
- * Selection-based formatting toolbar. Visible whenever the editor has a
12
- * non-empty range selection inside text content. Inline marks (B/I/S/Code)
13
- * are grouped together; Link sits after a separator since it's a different
14
- * kind of action.
15
- */
16
- export function FloatingToolbar({ editor }: FloatingToolbarProps) {
17
- const [pos, setPos] = useState<{ top: number; left: number } | null>(null)
18
- const [linkOpen, setLinkOpen] = useState(false)
19
- const [linkUrl, setLinkUrl] = useState('')
20
-
21
- useEffect(() => {
22
- const update = (): void => {
23
- const { from, to, empty } = editor.state.selection
24
- if (empty) { setPos(null); return }
25
- // Don't show on full-block selections (e.g. clicking a custom block).
26
- const slice = editor.state.doc.slice(from, to)
27
- if (slice.content.childCount === 0) { setPos(null); return }
28
- const start = editor.view.coordsAtPos(from)
29
- const end = editor.view.coordsAtPos(to)
30
- // Viewport-relative — pair with `position: fixed` below. The wrapper
31
- // around <EditorContent> is `position: relative`, so an absolute toolbar
32
- // would be positioned relative to it instead of the viewport.
33
- // Lift the toolbar above the selection. The value is the toolbar's full
34
- // height plus a small breathing gap; bump if the toolbar grows.
35
- const top = Math.min(start.top, end.top) - 48
36
- const left = (start.left + end.right) / 2
37
- setPos({ top, left })
38
- }
39
- const close = (): void => setPos(null)
40
- editor.on('selectionUpdate', update)
41
- editor.on('blur', close)
42
- // Keep the toolbar pinned to the selection when the page or any scroll
43
- // ancestor scrolls (capture phase catches inner scrollers too).
44
- window.addEventListener('scroll', update, true)
45
- window.addEventListener('resize', update)
46
- return () => {
47
- editor.off('selectionUpdate', update)
48
- editor.off('blur', close)
49
- window.removeEventListener('scroll', update, true)
50
- window.removeEventListener('resize', update)
51
- }
52
- }, [editor])
53
-
54
- const openLinkDialog = (): void => {
55
- const previousUrl = editor.getAttributes('link')['href'] as string | undefined
56
- setLinkUrl(previousUrl ?? '')
57
- setLinkOpen(true)
58
- }
59
-
60
- const applyLink = (): void => {
61
- setLinkOpen(false)
62
- const trimmed = linkUrl.trim()
63
- if (trimmed === '') {
64
- editor.chain().focus().extendMarkRange('link').unsetLink().run()
65
- return
66
- }
67
- editor.chain().focus().extendMarkRange('link').setLink({ href: trimmed }).run()
68
- }
69
-
70
- const removeLink = (): void => {
71
- setLinkOpen(false)
72
- editor.chain().focus().extendMarkRange('link').unsetLink().run()
73
- }
74
-
75
- const mod = isMac() ? '⌘' : 'Ctrl+'
76
- const isLink = editor.isActive('link')
77
-
78
- return (
79
- <>
80
- {pos && (
81
- <Tooltip.Provider delay={400}>
82
- <div
83
- className="fixed z-40 flex items-center gap-0.5 rounded-md border bg-popover px-1 py-1 text-popover-foreground shadow-md"
84
- style={{ top: pos.top, left: pos.left, transform: 'translateX(-50%)' }}
85
- >
86
- <ToolbarButton
87
- label={`Bold (${mod}B)`}
88
- active={editor.isActive('bold')}
89
- onClick={() => editor.chain().focus().toggleBold().run()}
90
- >
91
- <BoldIcon />
92
- </ToolbarButton>
93
- <ToolbarButton
94
- label={`Italic (${mod}I)`}
95
- active={editor.isActive('italic')}
96
- onClick={() => editor.chain().focus().toggleItalic().run()}
97
- >
98
- <ItalicIcon />
99
- </ToolbarButton>
100
- <ToolbarButton
101
- label={`Strikethrough (${mod}⇧X)`}
102
- active={editor.isActive('strike')}
103
- onClick={() => editor.chain().focus().toggleStrike().run()}
104
- >
105
- <StrikeIcon />
106
- </ToolbarButton>
107
- <ToolbarButton
108
- label={`Code (${mod}E)`}
109
- active={editor.isActive('code')}
110
- onClick={() => editor.chain().focus().toggleCode().run()}
111
- >
112
- <CodeIcon />
113
- </ToolbarButton>
114
- <span aria-hidden className="mx-1 h-5 w-px shrink-0 bg-border" />
115
- <ToolbarButton
116
- label={isLink ? 'Edit link' : 'Add link'}
117
- active={isLink}
118
- onClick={openLinkDialog}
119
- >
120
- <LinkIcon />
121
- </ToolbarButton>
122
- </div>
123
- </Tooltip.Provider>
124
- )}
125
- <LinkDialog
126
- open={linkOpen}
127
- onOpenChange={setLinkOpen}
128
- url={linkUrl}
129
- onUrlChange={setLinkUrl}
130
- onApply={applyLink}
131
- onRemove={isLink ? removeLink : null}
132
- isEdit={isLink}
133
- />
134
- </>
135
- )
136
- }
137
-
138
- function ToolbarButton({
139
- label,
140
- active,
141
- onClick,
142
- children,
143
- }: {
144
- label: string
145
- active: boolean
146
- onClick: () => void
147
- children: ReactNode
148
- }) {
149
- return (
150
- <Tooltip.Root>
151
- <Tooltip.Trigger
152
- render={(props) => (
153
- <button
154
- {...props}
155
- type="button"
156
- // mousedown + preventDefault keeps editor focus so the selection
157
- // (and therefore the toolbar) survives the click.
158
- onMouseDown={(e) => { e.preventDefault(); onClick() }}
159
- className={`inline-flex h-7 w-7 items-center justify-center rounded text-foreground transition-colors ${
160
- active ? 'bg-accent text-accent-foreground' : 'hover:bg-accent/60'
161
- }`}
162
- aria-label={label}
163
- aria-pressed={active}
164
- >
165
- {children}
166
- </button>
167
- )}
168
- />
169
- <Tooltip.Portal>
170
- <Tooltip.Positioner side="top" sideOffset={6} className="isolate z-50">
171
- <Tooltip.Popup className="rounded-md bg-foreground px-2 py-1 text-xs text-background shadow-md data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95">
172
- {label}
173
- </Tooltip.Popup>
174
- </Tooltip.Positioner>
175
- </Tooltip.Portal>
176
- </Tooltip.Root>
177
- )
178
- }
179
-
180
- function LinkDialog({
181
- open,
182
- onOpenChange,
183
- url,
184
- onUrlChange,
185
- onApply,
186
- onRemove,
187
- isEdit,
188
- }: {
189
- open: boolean
190
- onOpenChange: (open: boolean) => void
191
- url: string
192
- onUrlChange: (url: string) => void
193
- onApply: () => void
194
- onRemove: (() => void) | null
195
- isEdit: boolean
196
- }) {
197
- return (
198
- <Dialog.Root open={open} onOpenChange={onOpenChange}>
199
- <Dialog.Portal>
200
- <Dialog.Backdrop className="fixed inset-0 z-50 bg-black/50 transition-opacity duration-150 data-[starting-style]:opacity-0 data-[ending-style]:opacity-0" />
201
- <Dialog.Popup className="fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] sm:max-w-md translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg transition-[opacity,transform] duration-150 data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[ending-style]:scale-95 data-[ending-style]:opacity-0">
202
- <Dialog.Title className="text-lg leading-none font-semibold">
203
- {isEdit ? 'Edit link' : 'Add link'}
204
- </Dialog.Title>
205
- <input
206
- type="url"
207
- value={url}
208
- onChange={(e) => onUrlChange(e.target.value)}
209
- onKeyDown={(e) => {
210
- if (e.key === 'Enter') {
211
- e.preventDefault()
212
- onApply()
213
- }
214
- }}
215
- placeholder="https://example.com"
216
- autoFocus
217
- className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
218
- />
219
- <div className="flex flex-row-reverse items-center gap-2">
220
- <button
221
- type="button"
222
- onClick={onApply}
223
- className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-3 text-sm font-medium text-primary-foreground hover:bg-primary/90"
224
- >
225
- {isEdit ? 'Update' : 'Add'}
226
- </button>
227
- <button
228
- type="button"
229
- onClick={() => onOpenChange(false)}
230
- className="inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-3 text-sm font-medium hover:bg-accent hover:text-accent-foreground"
231
- >
232
- Cancel
233
- </button>
234
- {onRemove && (
235
- <button
236
- type="button"
237
- onClick={onRemove}
238
- className="me-auto inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium text-destructive hover:bg-destructive/10"
239
- >
240
- Remove link
241
- </button>
242
- )}
243
- </div>
244
- </Dialog.Popup>
245
- </Dialog.Portal>
246
- </Dialog.Root>
247
- )
248
- }
249
-
250
- function isMac(): boolean {
251
- if (typeof navigator === 'undefined') return false
252
- // navigator.platform is deprecated but still the most reliable signal here.
253
- return /Mac|iPhone|iPad|iPod/.test(navigator.platform)
254
- }
255
-
256
- // Inline SVG icons (lucide.dev paths). Kept inline so this package doesn't
257
- // pull `lucide-react` as a peer dep — the rest of @pilotiq/tiptap is already
258
- // inline-SVG (DragHandle).
259
- function BoldIcon() {
260
- return (
261
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
262
- <path d="M6 12h9a4 4 0 0 1 0 8H6Z" />
263
- <path d="M6 4h7a4 4 0 0 1 0 8H6Z" />
264
- </svg>
265
- )
266
- }
267
-
268
- function ItalicIcon() {
269
- return (
270
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
271
- <line x1="19" y1="4" x2="10" y2="4" />
272
- <line x1="14" y1="20" x2="5" y2="20" />
273
- <line x1="15" y1="4" x2="9" y2="20" />
274
- </svg>
275
- )
276
- }
277
-
278
- function StrikeIcon() {
279
- return (
280
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
281
- <path d="M16 4H9a3 3 0 0 0-2.83 4" />
282
- <path d="M14 12a4 4 0 0 1 0 8H6" />
283
- <line x1="4" y1="12" x2="20" y2="12" />
284
- </svg>
285
- )
286
- }
287
-
288
- function CodeIcon() {
289
- return (
290
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
291
- <polyline points="16 18 22 12 16 6" />
292
- <polyline points="8 6 2 12 8 18" />
293
- </svg>
294
- )
295
- }
296
-
297
- function LinkIcon() {
298
- return (
299
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
300
- <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
301
- <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
302
- </svg>
303
- )
304
- }