Full document, spreadsheet, slideshow, and diagram tooling
1import { Node, mergeAttributes } from '@tiptap/core';
2
3/**
4 * Toggle Block (collapsible section) — uses native <details>/<summary>.
5 *
6 * Creates a collapsible section in the document that the reader can
7 * expand/collapse by clicking the summary. Content inside is fully
8 * editable and collaborative via Yjs.
9 *
10 * Slash command: /toggle
11 */
12
13export const ToggleBlock = Node.create({
14 name: 'details',
15
16 group: 'block',
17 content: 'detailsSummary block+',
18 defining: true,
19
20 addAttributes() {
21 return {
22 open: {
23 default: true,
24 parseHTML: (el) => el.hasAttribute('open'),
25 renderHTML: (attrs) => (attrs.open ? { open: '' } : {}),
26 },
27 };
28 },
29
30 parseHTML() {
31 return [{ tag: 'details' }];
32 },
33
34 renderHTML({ HTMLAttributes }) {
35 return ['details', mergeAttributes(HTMLAttributes, { class: 'toggle-block' }), 0];
36 },
37
38 addCommands() {
39 return {
40 insertToggleBlock:
41 () =>
42 ({ commands }) => {
43 return commands.insertContent({
44 type: 'details',
45 attrs: { open: true },
46 content: [
47 { type: 'detailsSummary', content: [{ type: 'text', text: 'Toggle heading' }] },
48 { type: 'paragraph' },
49 ],
50 });
51 },
52 };
53 },
54});
55
56export const ToggleSummary = Node.create({
57 name: 'detailsSummary',
58
59 group: 'block',
60 content: 'inline*',
61 defining: true,
62
63 parseHTML() {
64 return [{ tag: 'summary' }];
65 },
66
67 renderHTML({ HTMLAttributes }) {
68 return ['summary', mergeAttributes(HTMLAttributes, { class: 'toggle-summary' }), 0];
69 },
70});