@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.
- package/CHANGELOG.md +751 -0
- package/boost/guidelines.md +268 -0
- package/boost/skills/pilotiq-tiptap-blocks/SKILL.md +48 -0
- package/boost/skills/pilotiq-tiptap-blocks/rules/custom-blocks.md +90 -0
- package/boost/skills/pilotiq-tiptap-blocks/rules/slash-menu-and-mentions.md +101 -0
- package/boost/skills/pilotiq-tiptap-blocks/rules/toolbar-and-extensibility.md +161 -0
- package/dist/markdownExtension.js +259 -164
- package/dist/react/BlockNodeView.d.ts +1 -1
- package/dist/react/FloatingToolbar.d.ts +1 -1
- package/dist/react/MentionMenu.d.ts +1 -1
- package/dist/react/Palette.d.ts +1 -1
- package/dist/react/SlashMenu.d.ts +1 -1
- package/dist/react/TableFloatingToolbar.d.ts +1 -1
- package/dist/react/TiptapEditor.d.ts +1 -1
- package/dist/react/Toolbar.d.ts +2 -2
- package/package.json +6 -4
- package/dist/Block.d.ts.map +0 -1
- package/dist/Block.js.map +0 -1
- package/dist/MentionProvider.d.ts.map +0 -1
- package/dist/MentionProvider.js.map +0 -1
- package/dist/PlainTextEditor.d.ts.map +0 -1
- package/dist/PlainTextEditor.js.map +0 -1
- package/dist/RichTextField.d.ts.map +0 -1
- package/dist/RichTextField.js.map +0 -1
- package/dist/extensions/AiInlineDiffExtension.d.ts.map +0 -1
- package/dist/extensions/AiInlineDiffExtension.js.map +0 -1
- package/dist/extensions/AiSuggestionExtension.d.ts.map +0 -1
- package/dist/extensions/AiSuggestionExtension.js.map +0 -1
- package/dist/extensions/BlockNodeExtension.d.ts.map +0 -1
- package/dist/extensions/BlockNodeExtension.js.map +0 -1
- package/dist/extensions/DragHandleExtension.d.ts.map +0 -1
- package/dist/extensions/DragHandleExtension.js.map +0 -1
- package/dist/extensions/GridExtension.d.ts.map +0 -1
- package/dist/extensions/GridExtension.js.map +0 -1
- package/dist/extensions/MentionExtension.d.ts.map +0 -1
- package/dist/extensions/MentionExtension.js.map +0 -1
- package/dist/extensions/MergeTagExtension.d.ts.map +0 -1
- package/dist/extensions/MergeTagExtension.js.map +0 -1
- package/dist/extensions/SlashCommandExtension.d.ts.map +0 -1
- package/dist/extensions/SlashCommandExtension.js.map +0 -1
- package/dist/extensions/TextSizeMarks.d.ts.map +0 -1
- package/dist/extensions/TextSizeMarks.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/markdownExtension.d.ts.map +0 -1
- package/dist/markdownStorage.d.ts.map +0 -1
- package/dist/markdownStorage.js.map +0 -1
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js.map +0 -1
- package/dist/react/AiSuggestionBanner.d.ts.map +0 -1
- package/dist/react/AiSuggestionBanner.js.map +0 -1
- package/dist/react/BlockNodeView.d.ts.map +0 -1
- package/dist/react/BlockNodeView.js.map +0 -1
- package/dist/react/BlockSidePanel.d.ts.map +0 -1
- package/dist/react/BlockSidePanel.js.map +0 -1
- package/dist/react/CollabTextRenderer.d.ts.map +0 -1
- package/dist/react/CollabTextRenderer.js.map +0 -1
- package/dist/react/FloatingToolbar.d.ts.map +0 -1
- package/dist/react/FloatingToolbar.js.map +0 -1
- package/dist/react/MarkdownEditor.d.ts.map +0 -1
- package/dist/react/MarkdownEditor.js.map +0 -1
- package/dist/react/MentionMenu.d.ts.map +0 -1
- package/dist/react/MentionMenu.js.map +0 -1
- package/dist/react/Palette.d.ts.map +0 -1
- package/dist/react/Palette.js.map +0 -1
- package/dist/react/SlashMenu.d.ts.map +0 -1
- package/dist/react/SlashMenu.js.map +0 -1
- package/dist/react/TableFloatingToolbar.d.ts.map +0 -1
- package/dist/react/TableFloatingToolbar.js.map +0 -1
- package/dist/react/TiptapEditor.d.ts.map +0 -1
- package/dist/react/TiptapEditor.js.map +0 -1
- package/dist/react/Toolbar.d.ts.map +0 -1
- package/dist/react/Toolbar.js.map +0 -1
- package/dist/react/toolbarButtons.d.ts.map +0 -1
- package/dist/react/toolbarButtons.js.map +0 -1
- package/dist/react/useAiInlineDiff.d.ts.map +0 -1
- package/dist/react/useAiInlineDiff.js.map +0 -1
- package/dist/react/useAiSuggestionBridge.d.ts.map +0 -1
- package/dist/react/useAiSuggestionBridge.js.map +0 -1
- package/dist/register.d.ts.map +0 -1
- package/dist/register.js.map +0 -1
- package/dist/render.d.ts.map +0 -1
- package/dist/render.js.map +0 -1
- package/dist/surgicalOps.d.ts.map +0 -1
- package/dist/surgicalOps.js.map +0 -1
- package/dist/test/setup.d.ts.map +0 -1
- package/dist/test/setup.js.map +0 -1
- package/src/Block.ts +0 -75
- package/src/MentionProvider.ts +0 -153
- package/src/PlainTextEditor.dom.test.ts +0 -111
- package/src/PlainTextEditor.test.ts +0 -158
- package/src/PlainTextEditor.ts +0 -229
- package/src/RichTextField.test.ts +0 -447
- package/src/RichTextField.ts +0 -508
- package/src/extensions/AiInlineDiffExtension.ts +0 -286
- package/src/extensions/AiSuggestionExtension.test.ts +0 -141
- package/src/extensions/AiSuggestionExtension.ts +0 -522
- package/src/extensions/BlockNodeExtension.ts +0 -134
- package/src/extensions/DragHandleExtension.ts +0 -184
- package/src/extensions/GridExtension.test.ts +0 -31
- package/src/extensions/GridExtension.ts +0 -138
- package/src/extensions/MentionExtension.ts +0 -248
- package/src/extensions/MergeTagExtension.ts +0 -75
- package/src/extensions/SlashCommandExtension.test.ts +0 -147
- package/src/extensions/SlashCommandExtension.ts +0 -332
- package/src/extensions/TextSizeMarks.ts +0 -73
- package/src/index.ts +0 -62
- package/src/markdownExtension.ts +0 -19
- package/src/markdownStorage.ts +0 -49
- package/src/plugin.test.ts +0 -19
- package/src/plugin.ts +0 -26
- package/src/react/AiSuggestionBanner.tsx +0 -185
- package/src/react/BlockNodeView.tsx +0 -99
- package/src/react/BlockSidePanel.dom.test.tsx +0 -38
- package/src/react/BlockSidePanel.test.ts +0 -412
- package/src/react/BlockSidePanel.tsx +0 -451
- package/src/react/CollabTextRenderer.tsx +0 -228
- package/src/react/FloatingToolbar.tsx +0 -304
- package/src/react/MarkdownEditor.tsx +0 -603
- package/src/react/MentionMenu.tsx +0 -120
- package/src/react/Palette.tsx +0 -86
- package/src/react/SlashMenu.tsx +0 -129
- package/src/react/TableFloatingToolbar.tsx +0 -154
- package/src/react/TiptapEditor.dom.test.tsx +0 -112
- package/src/react/TiptapEditor.tsx +0 -777
- package/src/react/Toolbar.tsx +0 -438
- package/src/react/toolbarButtons.tsx +0 -579
- package/src/react/useAiInlineDiff.ts +0 -342
- package/src/react/useAiSuggestionBridge.ts +0 -223
- package/src/register.test.ts +0 -14
- package/src/register.ts +0 -42
- package/src/render.test.ts +0 -745
- package/src/render.ts +0 -480
- package/src/surgicalOps.ts +0 -205
- package/src/test/setup.ts +0 -64
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Toolbar & Extensibility
|
|
2
|
+
|
|
3
|
+
Three things in scope here: customizing the always-on toolbar, opting into non-default block primitives (`details`, `grid`, `lead`, `small`), and the pitfalls that bite when you extend the editor beyond the defaults.
|
|
4
|
+
|
|
5
|
+
## Default toolbar layout
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
[
|
|
9
|
+
['bold', 'italic', 'underline', 'strike', 'subscript', 'superscript', 'link'],
|
|
10
|
+
['h2', 'h3'],
|
|
11
|
+
['alignStart', 'alignCenter', 'alignEnd'],
|
|
12
|
+
['blockquote', 'codeBlock', 'bulletList', 'orderedList'],
|
|
13
|
+
['undo', 'redo'],
|
|
14
|
+
]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Each inner array is a visually-separated group in the rendered toolbar. The selection-anchored floating toolbar (separate surface) shows a smaller subset on text selection — by default `bold / italic / link / clearFormatting`.
|
|
18
|
+
|
|
19
|
+
## Three customization styles
|
|
20
|
+
|
|
21
|
+
Use whichever matches your intent:
|
|
22
|
+
|
|
23
|
+
### Replace the whole layout
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
RichTextField.make('body').toolbarButtons([
|
|
27
|
+
['bold', 'italic', 'underline', 'strike', 'link'],
|
|
28
|
+
['h2', 'h3'],
|
|
29
|
+
['textColor', 'highlight'],
|
|
30
|
+
['bulletList', 'orderedList'],
|
|
31
|
+
['attachFiles', 'table', 'details', 'grid', 'gridDelete'],
|
|
32
|
+
['undo', 'redo'],
|
|
33
|
+
])
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Augment the defaults
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
RichTextField.make('body')
|
|
40
|
+
.enableToolbarButtons(['lead', 'small']) // append to last group
|
|
41
|
+
.disableToolbarButtons(['table']) // drop from every group
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`enableToolbarButtons` always appends to the last group; reach for `toolbarButtons` if you need ids in a specific group.
|
|
45
|
+
|
|
46
|
+
### Hide chrome entirely
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
RichTextField.make('body')
|
|
50
|
+
.toolbar(false) // hide the always-on top toolbar
|
|
51
|
+
.floatingToolbar(false) // disable the selection-anchored quick toolbar
|
|
52
|
+
.slashCommand(false) // disable the slash menu
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
All three are independent. A minimal-distraction config: `.toolbar(false).floatingToolbar(false)` but keep the slash menu so the user still has a way to insert blocks.
|
|
56
|
+
|
|
57
|
+
## Recognized button ids
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Inline marks bold italic underline strike subscript superscript code lead small
|
|
61
|
+
Headings paragraph h1 h2 h3 h4 h5 h6
|
|
62
|
+
Alignment alignStart alignCenter alignEnd alignJustify
|
|
63
|
+
Block prims blockquote codeBlock bulletList orderedList horizontalRule
|
|
64
|
+
Style textColor highlight clearFormatting
|
|
65
|
+
Files attachFiles
|
|
66
|
+
Tables table tableAddColumnBefore tableAddColumnAfter tableDeleteColumn
|
|
67
|
+
tableAddRowBefore tableAddRowAfter tableDeleteRow
|
|
68
|
+
tableMergeCells tableSplitCell tableDelete
|
|
69
|
+
tableToggleHeaderRow tableToggleHeaderCell
|
|
70
|
+
Disclosure details
|
|
71
|
+
Layout grid gridDelete
|
|
72
|
+
Editing link undo redo
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Unknown ids are silently dropped.** The union is forward-compatible — adding a new id later won't break existing field configs that referenced a typo or pre-release id.
|
|
76
|
+
|
|
77
|
+
## Opt-in primitives (not in default toolbar)
|
|
78
|
+
|
|
79
|
+
These nodes ship but aren't surfaced unless you explicitly add their toolbar id (or they appear in the slash menu via the same mechanism). The renderer (`renderRichTextToHtml`) serializes them whether or not the toolbar exposes them — so a document with `details` content created elsewhere still round-trips correctly even if the local field config doesn't include the button.
|
|
80
|
+
|
|
81
|
+
### `lead` / `small` size marks
|
|
82
|
+
|
|
83
|
+
Two inline marks for paragraph-style size variants:
|
|
84
|
+
|
|
85
|
+
- **`lead`** renders as `<span class="lead">…</span>`. Consumer owns the `.lead` CSS — there's no built-in stylesheet (`@pilotiq/pilotiq`'s typography preset typically has one; check yours).
|
|
86
|
+
- **`small`** renders as semantic `<small>…</small>`.
|
|
87
|
+
|
|
88
|
+
Surfaced as toolbar button ids `'lead'` / `'small'` and slash-menu entries under the **Style** group. Mirror the editor output in your own server-side render (`renderRichTextToHtml` does this correctly).
|
|
89
|
+
|
|
90
|
+
### `details` (collapsible disclosure)
|
|
91
|
+
|
|
92
|
+
A node trio (`details` / `detailsSummary` / `detailsContent`) wired from `@tiptap/extension-details@3.22.4` — v3 consolidated the three classes into a single peer dep (the `-summary` / `-content` child packages don't exist on the v3 line).
|
|
93
|
+
|
|
94
|
+
- Toolbar id: `'details'` (opt-in)
|
|
95
|
+
- Slash entry under the **Insert** group
|
|
96
|
+
- Render emits standard `<details><summary>…</summary>…</details>` HTML
|
|
97
|
+
- Open / closed state round-trips via the node's `open: boolean` attr; the renderer adds the platform `open` attribute when `attrs.open === true`
|
|
98
|
+
|
|
99
|
+
### `grid` / `gridDelete` (2-column / 3-column layout)
|
|
100
|
+
|
|
101
|
+
A node pair (`grid` + `gridColumn`) defined inline under `extensions/GridExtension.ts` — Tiptap doesn't ship a first-party grid extension. Schema constrains `grid` to `gridColumn{2,3}` so the user can't construct a 1-col or 4+-col grid through any path (toolbar / slash / paste).
|
|
102
|
+
|
|
103
|
+
- Toolbar ids: `'grid'` (insert; defaults to 2 columns when clicked) + `'gridDelete'` (unwrap the enclosing grid)
|
|
104
|
+
- Slash entries: `Two-column grid`, `Three-column grid` under the **Insert** group
|
|
105
|
+
- Render emits `<div class="pilotiq-grid pilotiq-grid-cols-N">…<div>col</div>…</div>` — consumer owns the CSS (same posture as `lead` / `small`)
|
|
106
|
+
- Out-of-range column counts (anything other than 2 or 3) clamp to 2 in both editor `parseHTML` and renderer. `clampGridColumns(value)` is exported from `GridExtension.ts` for tests; the render-side has its own micro-helper to keep `render.ts` Tiptap-runtime-free.
|
|
107
|
+
|
|
108
|
+
## File attachments (`attachFiles` button)
|
|
109
|
+
|
|
110
|
+
The `attachFiles` toolbar button uploads via the panel's registered `UploadAdapter`. Per-field setters:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
RichTextField.make('body')
|
|
114
|
+
.fileAttachmentsAcceptedFileTypes(['image/*', 'application/pdf'])
|
|
115
|
+
.fileAttachmentsMaxSize(5 * 1024 * 1024) // 5 MB cap
|
|
116
|
+
.fileAttachmentsDirectory('articles') // sub-directory hint
|
|
117
|
+
.fileAttachmentsVisibility('public') // adapter-dependent
|
|
118
|
+
.resizableImages() // drag-handle resize on images
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The upload route enforces `maxSize` server-side — a tampered client can't bypass. **Without an `UploadAdapter` registered on the panel, the `attachFiles` button silently hides.** Wire one with `Pilotiq.uploads({ adapter: localUpload({...}) })` (or any adapter from `@pilotiq/media`, S3, R2, etc.).
|
|
122
|
+
|
|
123
|
+
This auto-hide behavior is intentional — see [[feedback-pilotiq-panel-module-client-safe]]: the `attachFiles` button checks `RenderContext.hasUploadAdapter` at meta-resolve time. The field renders correctly with the button absent rather than showing a broken control.
|
|
124
|
+
|
|
125
|
+
## Drag handle — three-step drop dance
|
|
126
|
+
|
|
127
|
+
The framework ships per-block drag handles in `extensions/DragHandleExtension.ts`. If you write a **custom block with external drag UX** (not the default per-block handle), the drop handler must do three things or you get the dreaded snap-back-to-origin bug:
|
|
128
|
+
|
|
129
|
+
1. **`setNodeSelection(pos)`** on the editor view to select the drop target
|
|
130
|
+
2. **Set `view.dragging = { slice, move: true }`** before the drop dispatches
|
|
131
|
+
3. **`serializeForClipboard(view, slice)`** so ProseMirror has the serialized content to insert
|
|
132
|
+
|
|
133
|
+
Missing any one of the three causes the dragged node to disappear from its drop position and snap back to where it came from. The framework's built-in handle does all three correctly; custom drag implementations (e.g. an external palette dragging onto the canvas) must too. See [[feedback-tiptap-drag-handle-pm-dragging]] for the full repro.
|
|
134
|
+
|
|
135
|
+
## Module identity — dedupe Tiptap peers
|
|
136
|
+
|
|
137
|
+
`@tiptap/core` and `@tiptap/pm` keep state on module-level singletons. **Multiple copies break the editor** (silent: `instanceof` checks fail, schema lookups miss, NodeViews don't mount). Add them to `resolve.dedupe` in your Vite config:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
// vite.config.ts
|
|
141
|
+
export default defineConfig({
|
|
142
|
+
resolve: {
|
|
143
|
+
dedupe: ['@tiptap/core', '@tiptap/pm', '@tiptap/react'],
|
|
144
|
+
},
|
|
145
|
+
// …
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This is unrelated to pilotiq's general `optimizeDeps.exclude: ['@pilotiq/pilotiq']` rule (see [[feedback-vite-optimizedeps-exclude]]) — both can be needed simultaneously.
|
|
150
|
+
|
|
151
|
+
## Toolbar-driven slash entries
|
|
152
|
+
|
|
153
|
+
The slash menu's **Style** and **Format** groups derive from the *active* toolbar buttons. If you hide `textColor` from the toolbar via `.disableToolbarButtons(['textColor'])`, it also disappears from the slash menu. Same for alignment — if no `alignStart` / `alignCenter` / `alignEnd` button is active, the Format group is empty and collapses.
|
|
154
|
+
|
|
155
|
+
The **Insert** group is the inverse: it always shows the core insertable nodes regardless of toolbar config (paragraph, headings, lists, code block, blockquote, horizontal rule). Opt-in primitives (`details`, `grid`) only appear in the Insert group when their toolbar id is in the active config.
|
|
156
|
+
|
|
157
|
+
## See also
|
|
158
|
+
|
|
159
|
+
- `custom-blocks.md` — `Block.make(...)` user blocks appear in the slash menu after the framework groups.
|
|
160
|
+
- `slash-menu-and-mentions.md` — how merge tags and mentions interact with the slash menu surface.
|
|
161
|
+
- [[feedback-tiptap-block-name-collision]] — the `'block'` name pitfall (also covered in `custom-blocks.md`).
|