@tiptap/extension-details 3.20.6 → 3.22.0
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/index.cjs +34 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +34 -4
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/details.ts +59 -3
package/dist/index.cjs
CHANGED
|
@@ -107,7 +107,10 @@ var Details = import_core2.Node.create({
|
|
|
107
107
|
return {
|
|
108
108
|
persist: false,
|
|
109
109
|
openClassName: "is-open",
|
|
110
|
-
HTMLAttributes: {}
|
|
110
|
+
HTMLAttributes: {},
|
|
111
|
+
renderToggleButton: ({ element, isOpen }) => {
|
|
112
|
+
element.setAttribute("aria-label", isOpen ? "Collapse details content" : "Expand details content");
|
|
113
|
+
}
|
|
111
114
|
};
|
|
112
115
|
},
|
|
113
116
|
addAttributes() {
|
|
@@ -150,10 +153,17 @@ var Details = import_core2.Node.create({
|
|
|
150
153
|
Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value));
|
|
151
154
|
const toggle = document.createElement("button");
|
|
152
155
|
toggle.type = "button";
|
|
156
|
+
const renderToggleButton = (options) => {
|
|
157
|
+
this.options.renderToggleButton({
|
|
158
|
+
element: toggle,
|
|
159
|
+
...options
|
|
160
|
+
});
|
|
161
|
+
};
|
|
153
162
|
dom.append(toggle);
|
|
154
163
|
const content = document.createElement("div");
|
|
155
164
|
dom.append(content);
|
|
156
|
-
const toggleDetailsContent = (
|
|
165
|
+
const toggleDetailsContent = (options) => {
|
|
166
|
+
const { setToValue, node: currentNode = node } = options || {};
|
|
157
167
|
if (setToValue !== void 0) {
|
|
158
168
|
if (setToValue) {
|
|
159
169
|
if (dom.classList.contains(this.options.openClassName)) {
|
|
@@ -169,10 +179,19 @@ var Details = import_core2.Node.create({
|
|
|
169
179
|
} else {
|
|
170
180
|
dom.classList.toggle(this.options.openClassName);
|
|
171
181
|
}
|
|
182
|
+
const isOpen = dom.classList.contains(this.options.openClassName);
|
|
183
|
+
renderToggleButton({
|
|
184
|
+
isOpen,
|
|
185
|
+
node: currentNode
|
|
186
|
+
});
|
|
172
187
|
const event = new Event("toggleDetailsContent");
|
|
173
188
|
const detailsContent = content.querySelector(':scope > div[data-type="detailsContent"]');
|
|
174
189
|
detailsContent == null ? void 0 : detailsContent.dispatchEvent(event);
|
|
175
190
|
};
|
|
191
|
+
renderToggleButton({
|
|
192
|
+
isOpen: Boolean(node.attrs.open),
|
|
193
|
+
node
|
|
194
|
+
});
|
|
176
195
|
if (node.attrs.open) {
|
|
177
196
|
setTimeout(() => toggleDetailsContent());
|
|
178
197
|
}
|
|
@@ -210,14 +229,25 @@ var Details = import_core2.Node.create({
|
|
|
210
229
|
if (mutation.type === "selection") {
|
|
211
230
|
return false;
|
|
212
231
|
}
|
|
213
|
-
|
|
232
|
+
const target = mutation.target;
|
|
233
|
+
const isInsideWrapper = dom.contains(target);
|
|
234
|
+
const isInsideToggleButton = toggle.contains(target);
|
|
235
|
+
return isInsideToggleButton || !isInsideWrapper || dom === target;
|
|
214
236
|
},
|
|
215
237
|
update: (updatedNode) => {
|
|
216
238
|
if (updatedNode.type !== this.type) {
|
|
217
239
|
return false;
|
|
218
240
|
}
|
|
219
241
|
if (updatedNode.attrs.open !== void 0) {
|
|
220
|
-
toggleDetailsContent(
|
|
242
|
+
toggleDetailsContent({
|
|
243
|
+
setToValue: updatedNode.attrs.open,
|
|
244
|
+
node: updatedNode
|
|
245
|
+
});
|
|
246
|
+
} else {
|
|
247
|
+
renderToggleButton({
|
|
248
|
+
isOpen: dom.classList.contains(this.options.openClassName),
|
|
249
|
+
node: updatedNode
|
|
250
|
+
});
|
|
221
251
|
}
|
|
222
252
|
return true;
|
|
223
253
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/details.ts","../src/helpers/isNodeVisible.ts","../src/helpers/findClosestVisibleNode.ts","../src/helpers/setGapCursor.ts","../src/content/details-content.ts","../src/summary/details-summary.ts"],"sourcesContent":["import { Details } from './details.js'\n\nexport * from './content/index.js'\nexport * from './details.js'\nexport * from './summary/index.js'\n\nexport default Details\n","import {\n createBlockMarkdownSpec,\n defaultBlockAt,\n findChildren,\n findParentNode,\n isActive,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { findClosestVisibleNode } from './helpers/findClosestVisibleNode.js'\nimport { isNodeVisible } from './helpers/isNodeVisible.js'\nimport { setGapCursor } from './helpers/setGapCursor.js'\n\nexport interface DetailsOptions {\n /**\n * Specify if the open status should be saved in the document. Defaults to `false`.\n */\n persist: boolean\n /**\n * Specifies a CSS class that is set when toggling the content. Defaults to `is-open`.\n */\n openClassName: string\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n details: {\n /**\n * Set a details node\n */\n setDetails: () => ReturnType\n /**\n * Unset a details node\n */\n unsetDetails: () => ReturnType\n }\n }\n}\n\nexport const Details = Node.create<DetailsOptions>({\n name: 'details',\n\n content: 'detailsSummary detailsContent',\n\n group: 'block',\n\n defining: true,\n\n isolating: true,\n\n // @ts-ignore reason: `allowGapCursor` is not a valid property by default, but the `GapCursor` extension adds it to the Nodeconfig type\n allowGapCursor: false,\n\n addOptions() {\n return {\n persist: false,\n openClassName: 'is-open',\n HTMLAttributes: {},\n }\n },\n\n addAttributes() {\n if (!this.options.persist) {\n return []\n }\n\n return {\n open: {\n default: false,\n parseHTML: element => element.hasAttribute('open'),\n renderHTML: ({ open }) => {\n if (!open) {\n return {}\n }\n\n return { open: '' }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'details',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['details', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'details',\n content: 'block',\n }),\n\n addNodeView() {\n return ({ editor, getPos, node, HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n const toggle = document.createElement('button')\n\n toggle.type = 'button'\n\n dom.append(toggle)\n\n const content = document.createElement('div')\n\n dom.append(content)\n\n const toggleDetailsContent = (setToValue?: boolean) => {\n if (setToValue !== undefined) {\n if (setToValue) {\n if (dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.add(this.options.openClassName)\n } else {\n if (!dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.remove(this.options.openClassName)\n }\n } else {\n dom.classList.toggle(this.options.openClassName)\n }\n\n const event = new Event('toggleDetailsContent')\n const detailsContent = content.querySelector(':scope > div[data-type=\"detailsContent\"]')\n\n detailsContent?.dispatchEvent(event)\n }\n\n if (node.attrs.open) {\n setTimeout(() => toggleDetailsContent())\n }\n\n toggle.addEventListener('click', () => {\n toggleDetailsContent()\n\n if (!this.options.persist) {\n editor.commands.focus(undefined, { scrollIntoView: false })\n\n return\n }\n\n if (editor.isEditable && typeof getPos === 'function') {\n const { from, to } = editor.state.selection\n\n editor\n .chain()\n .command(({ tr }) => {\n const pos = getPos()\n\n if (!pos) {\n return false\n }\n\n const currentNode = tr.doc.nodeAt(pos)\n\n if (currentNode?.type !== this.type) {\n return false\n }\n\n tr.setNodeMarkup(pos, undefined, {\n open: !currentNode.attrs.open,\n })\n\n return true\n })\n .setTextSelection({\n from,\n to,\n })\n .focus(undefined, { scrollIntoView: false })\n .run()\n }\n })\n\n return {\n dom,\n contentDOM: content,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n // Only update the open state if set\n if (updatedNode.attrs.open !== undefined) {\n toggleDetailsContent(updatedNode.attrs.open)\n }\n\n return true\n },\n }\n }\n },\n\n addCommands() {\n return {\n setDetails:\n () =>\n ({ state, chain }) => {\n const { schema, selection } = state\n const { $from, $to } = selection\n const range = $from.blockRange($to)\n\n if (!range) {\n return false\n }\n\n const slice = state.doc.slice(range.start, range.end)\n const match = schema.nodes.detailsContent.contentMatch.matchFragment(slice.content)\n\n if (!match) {\n return false\n }\n\n const content = slice.toJSON()?.content || []\n\n return chain()\n .insertContentAt(\n { from: range.start, to: range.end },\n {\n type: this.name,\n content: [\n {\n type: 'detailsSummary',\n },\n {\n type: 'detailsContent',\n content,\n },\n ],\n },\n )\n .setTextSelection(range.start + 2)\n .run()\n },\n\n unsetDetails:\n () =>\n ({ state, chain }) => {\n const { selection, schema } = state\n const details = findParentNode(node => node.type === this.type)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsSummaries = findChildren(details.node, node => node.type === schema.nodes.detailsSummary)\n const detailsContents = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsSummaries.length || !detailsContents.length) {\n return false\n }\n\n const detailsSummary = detailsSummaries[0]\n const detailsContent = detailsContents[0]\n const from = details.pos\n const $from = state.doc.resolve(from)\n const to = from + details.node.nodeSize\n const range = { from, to }\n const content = (detailsContent.node.content.toJSON() as []) || []\n const defaultTypeForSummary = $from.parent.type.contentMatch.defaultType\n\n // TODO: this may break for some custom schemas\n const summaryContent = defaultTypeForSummary?.create(null, detailsSummary.node.content).toJSON()\n const mergedContent = [summaryContent, ...content]\n\n return chain()\n .insertContentAt(range, mergedContent)\n .setTextSelection(from + 1)\n .run()\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { schema, selection } = this.editor.state\n const { empty, $anchor } = selection\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n // for some reason safari removes the whole text content within a `<summary>`tag on backspace\n // so we have to remove the text manually\n // see: https://discuss.prosemirror.net/t/safari-backspace-bug-with-details-tag/4223\n if ($anchor.parentOffset !== 0) {\n return this.editor.commands.command(({ tr }) => {\n const from = $anchor.pos - 1\n const to = $anchor.pos\n\n tr.delete(from, to)\n\n return true\n })\n }\n\n return this.editor.commands.unsetDetails()\n },\n\n // Creates a new node below it if it is closed.\n // Otherwise inside `DetailsContent`.\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { schema, selection } = state\n const { $head } = selection\n\n if ($head.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n const isVisible = isNodeVisible($head.after() + 1, editor)\n const above = isVisible ? state.doc.nodeAt($head.after()) : $head.node(-2)\n\n if (!above) {\n return false\n }\n\n const after = isVisible ? 0 : $head.indexAfter(-1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const pos = isVisible ? $head.after() + 1 : $head.after(-1)\n const tr = state.tr.replaceWith(pos, pos, node)\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowRight: ({ editor }) => {\n return setGapCursor(editor, 'right')\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowDown: ({ editor }) => {\n return setGapCursor(editor, 'down')\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [\n // This plugin prevents text selections within the hidden content in `DetailsContent`.\n // The cursor is moved to the next visible position.\n new Plugin({\n key: new PluginKey('detailsSelection'),\n appendTransaction: (transactions, oldState, newState) => {\n const { editor, type } = this\n const isComposing = editor.view.composing\n\n if (isComposing) {\n return\n }\n\n const selectionSet = transactions.some(transaction => transaction.selectionSet)\n\n if (!selectionSet || !oldState.selection.empty || !newState.selection.empty) {\n return\n }\n\n const detailsIsActive = isActive(newState, type.name)\n\n if (!detailsIsActive) {\n return\n }\n\n const { $from } = newState.selection\n const isVisible = isNodeVisible($from.pos, editor)\n\n if (isVisible) {\n return\n }\n\n const details = findClosestVisibleNode($from, node => node.type === type, editor)\n\n if (!details) {\n return\n }\n\n const detailsSummaries = findChildren(\n details.node,\n node => node.type === newState.schema.nodes.detailsSummary,\n )\n\n if (!detailsSummaries.length) {\n return\n }\n\n const detailsSummary = detailsSummaries[0]\n const selectionDirection = oldState.selection.from < newState.selection.from ? 'forward' : 'backward'\n const correctedPosition =\n selectionDirection === 'forward'\n ? details.start + detailsSummary.pos\n : details.pos + detailsSummary.pos + detailsSummary.node.nodeSize\n const selection = TextSelection.create(newState.doc, correctedPosition)\n const transaction = newState.tr.setSelection(selection)\n\n return transaction\n },\n }),\n ]\n },\n})\n","import type { Editor } from '@tiptap/core'\n\nexport const isNodeVisible = (position: number, editor: Editor): boolean => {\n const node = editor.view.domAtPos(position).node as HTMLElement\n const isOpen = node.offsetParent !== null\n\n return isOpen\n}\n","import type { Editor, Predicate } from '@tiptap/core'\nimport type { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const findClosestVisibleNode = (\n $pos: ResolvedPos,\n predicate: Predicate,\n editor: Editor,\n):\n | {\n pos: number\n start: number\n depth: number\n node: ProseMirrorNode\n }\n | undefined => {\n for (let i = $pos.depth; i > 0; i -= 1) {\n const node = $pos.node(i)\n const match = predicate(node)\n const isVisible = isNodeVisible($pos.start(i), editor)\n\n if (match && isVisible) {\n return {\n pos: i > 0 ? $pos.before(i) : 0,\n start: $pos.start(i),\n depth: i,\n node,\n }\n }\n }\n}\n","import type { Editor } from '@tiptap/core'\nimport { findChildren, findParentNode } from '@tiptap/core'\nimport { GapCursor } from '@tiptap/pm/gapcursor'\nimport type { ResolvedPos } from '@tiptap/pm/model'\nimport type { Selection } from '@tiptap/pm/state'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const setGapCursor = (editor: Editor, direction: 'down' | 'right') => {\n const { state, view, extensionManager } = editor\n const { schema, selection } = state\n const { empty, $anchor } = selection\n const hasGapCursorExtension = !!extensionManager.extensions.find(extension => extension.name === 'gapCursor')\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary || !hasGapCursorExtension) {\n return false\n }\n\n if (direction === 'right' && $anchor.parentOffset !== $anchor.parent.nodeSize - 2) {\n return false\n }\n\n const details = findParentNode(node => node.type === schema.nodes.details)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsContent = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsContent.length) {\n return false\n }\n\n const isOpen = isNodeVisible(details.start + detailsContent[0].pos + 1, editor)\n\n if (isOpen) {\n return false\n }\n\n const $position = state.doc.resolve(details.pos + details.node.nodeSize)\n const $validPosition = GapCursor.findFrom($position, 1, false) as unknown as null | ResolvedPos\n\n if (!$validPosition) {\n return false\n }\n\n const { tr } = state\n const gapCursorSelection = new GapCursor($validPosition) as Selection\n\n tr.setSelection(gapCursorSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n}\n","import { createBlockMarkdownSpec, defaultBlockAt, findParentNode, mergeAttributes, Node } from '@tiptap/core'\nimport { Selection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nexport interface DetailsContentOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsContent = Node.create<DetailsContentOptions>({\n name: 'detailsContent',\n\n content: 'block+',\n\n defining: true,\n\n selectable: false,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: `div[data-type=\"${this.name}\"]`,\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 'data-type': this.name }), 0]\n },\n\n addNodeView() {\n return ({ HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n hidden: 'hidden',\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n dom.addEventListener('toggleDetailsContent', () => {\n dom.toggleAttribute('hidden')\n })\n\n return {\n dom,\n contentDOM: dom,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n return true\n },\n }\n }\n },\n\n addKeyboardShortcuts() {\n return {\n // Escape node on double enter\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { selection } = state\n const { $from, empty } = selection\n const detailsContent = findParentNode(node => node.type === this.type)(selection)\n\n if (!empty || !detailsContent || !detailsContent.node.childCount) {\n return false\n }\n\n const fromIndex = $from.index(detailsContent.depth)\n const { childCount } = detailsContent.node\n const isAtEnd = childCount === fromIndex + 1\n\n if (!isAtEnd) {\n return false\n }\n\n const defaultChildType = detailsContent.node.type.contentMatch.defaultType\n const defaultChildNode = defaultChildType?.createAndFill()\n\n if (!defaultChildNode) {\n return false\n }\n\n const $childPos = state.doc.resolve(detailsContent.pos + 1)\n const lastChildIndex = childCount - 1\n const lastChildNode = detailsContent.node.child(lastChildIndex)\n const lastChildPos = $childPos.posAtIndex(lastChildIndex, detailsContent.depth)\n const lastChildNodeIsEmpty = lastChildNode.eq(defaultChildNode)\n\n if (!lastChildNodeIsEmpty) {\n return false\n }\n\n // get parent of details node\n const above = $from.node(-3)\n\n if (!above) {\n return false\n }\n\n // get default node type after details node\n const after = $from.indexAfter(-3)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const { tr } = state\n const pos = $from.after(-2)\n\n tr.replaceWith(pos, pos, node)\n\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n\n const deleteFrom = lastChildPos\n const deleteTo = lastChildPos + lastChildNode.nodeSize\n\n tr.delete(deleteFrom, deleteTo)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n }\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsContent',\n }),\n})\n","import { createBlockMarkdownSpec, mergeAttributes, Node } from '@tiptap/core'\n\nexport interface DetailsSummaryOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsSummary = Node.create<DetailsSummaryOptions>({\n name: 'detailsSummary',\n\n content: 'text*',\n\n defining: true,\n\n selectable: false,\n\n isolating: true,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'summary',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['summary', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsSummary',\n content: 'inline',\n }),\n})\n"],"mappings":"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","names":["import_core","transaction","import_core","import_state","node","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/details.ts","../src/helpers/isNodeVisible.ts","../src/helpers/findClosestVisibleNode.ts","../src/helpers/setGapCursor.ts","../src/content/details-content.ts","../src/summary/details-summary.ts"],"sourcesContent":["import { Details } from './details.js'\n\nexport * from './content/index.js'\nexport * from './details.js'\nexport * from './summary/index.js'\n\nexport default Details\n","import {\n createBlockMarkdownSpec,\n defaultBlockAt,\n findChildren,\n findParentNode,\n isActive,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { findClosestVisibleNode } from './helpers/findClosestVisibleNode.js'\nimport { isNodeVisible } from './helpers/isNodeVisible.js'\nimport { setGapCursor } from './helpers/setGapCursor.js'\n\nexport interface DetailsRenderToggleButtonOptions {\n /**\n * The toggle button element rendered by the node view.\n */\n element: HTMLButtonElement\n /**\n * The current open state of the details node.\n */\n isOpen: boolean\n /**\n * The current node used to derive toggle button state.\n */\n node: ProseMirrorNode\n}\n\nexport interface DetailsOptions {\n /**\n * Specify if the open status should be saved in the document. Defaults to `false`.\n */\n persist: boolean\n /**\n * Specifies a CSS class that is set when toggling the content. Defaults to `is-open`.\n */\n openClassName: string\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n /**\n * Customizes the rendered toggle button.\n */\n renderToggleButton: (options: DetailsRenderToggleButtonOptions) => void\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n details: {\n /**\n * Set a details node\n */\n setDetails: () => ReturnType\n /**\n * Unset a details node\n */\n unsetDetails: () => ReturnType\n }\n }\n}\n\nexport const Details = Node.create<DetailsOptions>({\n name: 'details',\n\n content: 'detailsSummary detailsContent',\n\n group: 'block',\n\n defining: true,\n\n isolating: true,\n\n // @ts-ignore reason: `allowGapCursor` is not a valid property by default, but the `GapCursor` extension adds it to the Nodeconfig type\n allowGapCursor: false,\n\n addOptions() {\n return {\n persist: false,\n openClassName: 'is-open',\n HTMLAttributes: {},\n renderToggleButton: ({ element, isOpen }) => {\n element.setAttribute('aria-label', isOpen ? 'Collapse details content' : 'Expand details content')\n },\n }\n },\n\n addAttributes() {\n if (!this.options.persist) {\n return []\n }\n\n return {\n open: {\n default: false,\n parseHTML: element => element.hasAttribute('open'),\n renderHTML: ({ open }) => {\n if (!open) {\n return {}\n }\n\n return { open: '' }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'details',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['details', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'details',\n content: 'block',\n }),\n\n addNodeView() {\n return ({ editor, getPos, node, HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n const toggle = document.createElement('button')\n\n toggle.type = 'button'\n\n const renderToggleButton = (options: Omit<DetailsRenderToggleButtonOptions, 'element'>) => {\n this.options.renderToggleButton({\n element: toggle,\n ...options,\n })\n }\n\n dom.append(toggle)\n\n const content = document.createElement('div')\n\n dom.append(content)\n\n const toggleDetailsContent = (options?: { setToValue?: boolean; node?: ProseMirrorNode }) => {\n const { setToValue, node: currentNode = node } = options || {}\n\n if (setToValue !== undefined) {\n if (setToValue) {\n if (dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.add(this.options.openClassName)\n } else {\n if (!dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.remove(this.options.openClassName)\n }\n } else {\n dom.classList.toggle(this.options.openClassName)\n }\n\n const isOpen = dom.classList.contains(this.options.openClassName)\n\n renderToggleButton({\n isOpen,\n node: currentNode,\n })\n\n const event = new Event('toggleDetailsContent')\n const detailsContent = content.querySelector(':scope > div[data-type=\"detailsContent\"]')\n\n detailsContent?.dispatchEvent(event)\n }\n\n renderToggleButton({\n isOpen: Boolean(node.attrs.open),\n node,\n })\n\n if (node.attrs.open) {\n setTimeout(() => toggleDetailsContent())\n }\n\n toggle.addEventListener('click', () => {\n toggleDetailsContent()\n\n if (!this.options.persist) {\n editor.commands.focus(undefined, { scrollIntoView: false })\n\n return\n }\n\n if (editor.isEditable && typeof getPos === 'function') {\n const { from, to } = editor.state.selection\n\n editor\n .chain()\n .command(({ tr }) => {\n const pos = getPos()\n\n if (!pos) {\n return false\n }\n\n const currentNode = tr.doc.nodeAt(pos)\n\n if (currentNode?.type !== this.type) {\n return false\n }\n\n tr.setNodeMarkup(pos, undefined, {\n open: !currentNode.attrs.open,\n })\n\n return true\n })\n .setTextSelection({\n from,\n to,\n })\n .focus(undefined, { scrollIntoView: false })\n .run()\n }\n })\n\n return {\n dom,\n contentDOM: content,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n const target = mutation.target\n const isInsideWrapper = dom.contains(target)\n const isInsideToggleButton = toggle.contains(target)\n\n return isInsideToggleButton || !isInsideWrapper || dom === target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n // Only update the open state if set\n if (updatedNode.attrs.open !== undefined) {\n toggleDetailsContent({\n setToValue: updatedNode.attrs.open,\n node: updatedNode,\n })\n } else {\n renderToggleButton({\n isOpen: dom.classList.contains(this.options.openClassName),\n node: updatedNode,\n })\n }\n\n return true\n },\n }\n }\n },\n\n addCommands() {\n return {\n setDetails:\n () =>\n ({ state, chain }) => {\n const { schema, selection } = state\n const { $from, $to } = selection\n const range = $from.blockRange($to)\n\n if (!range) {\n return false\n }\n\n const slice = state.doc.slice(range.start, range.end)\n const match = schema.nodes.detailsContent.contentMatch.matchFragment(slice.content)\n\n if (!match) {\n return false\n }\n\n const content = slice.toJSON()?.content || []\n\n return chain()\n .insertContentAt(\n { from: range.start, to: range.end },\n {\n type: this.name,\n content: [\n {\n type: 'detailsSummary',\n },\n {\n type: 'detailsContent',\n content,\n },\n ],\n },\n )\n .setTextSelection(range.start + 2)\n .run()\n },\n\n unsetDetails:\n () =>\n ({ state, chain }) => {\n const { selection, schema } = state\n const details = findParentNode(node => node.type === this.type)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsSummaries = findChildren(details.node, node => node.type === schema.nodes.detailsSummary)\n const detailsContents = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsSummaries.length || !detailsContents.length) {\n return false\n }\n\n const detailsSummary = detailsSummaries[0]\n const detailsContent = detailsContents[0]\n const from = details.pos\n const $from = state.doc.resolve(from)\n const to = from + details.node.nodeSize\n const range = { from, to }\n const content = (detailsContent.node.content.toJSON() as []) || []\n const defaultTypeForSummary = $from.parent.type.contentMatch.defaultType\n\n // TODO: this may break for some custom schemas\n const summaryContent = defaultTypeForSummary?.create(null, detailsSummary.node.content).toJSON()\n const mergedContent = [summaryContent, ...content]\n\n return chain()\n .insertContentAt(range, mergedContent)\n .setTextSelection(from + 1)\n .run()\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { schema, selection } = this.editor.state\n const { empty, $anchor } = selection\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n // for some reason safari removes the whole text content within a `<summary>`tag on backspace\n // so we have to remove the text manually\n // see: https://discuss.prosemirror.net/t/safari-backspace-bug-with-details-tag/4223\n if ($anchor.parentOffset !== 0) {\n return this.editor.commands.command(({ tr }) => {\n const from = $anchor.pos - 1\n const to = $anchor.pos\n\n tr.delete(from, to)\n\n return true\n })\n }\n\n return this.editor.commands.unsetDetails()\n },\n\n // Creates a new node below it if it is closed.\n // Otherwise inside `DetailsContent`.\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { schema, selection } = state\n const { $head } = selection\n\n if ($head.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n const isVisible = isNodeVisible($head.after() + 1, editor)\n const above = isVisible ? state.doc.nodeAt($head.after()) : $head.node(-2)\n\n if (!above) {\n return false\n }\n\n const after = isVisible ? 0 : $head.indexAfter(-1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const pos = isVisible ? $head.after() + 1 : $head.after(-1)\n const tr = state.tr.replaceWith(pos, pos, node)\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowRight: ({ editor }) => {\n return setGapCursor(editor, 'right')\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowDown: ({ editor }) => {\n return setGapCursor(editor, 'down')\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [\n // This plugin prevents text selections within the hidden content in `DetailsContent`.\n // The cursor is moved to the next visible position.\n new Plugin({\n key: new PluginKey('detailsSelection'),\n appendTransaction: (transactions, oldState, newState) => {\n const { editor, type } = this\n const isComposing = editor.view.composing\n\n if (isComposing) {\n return\n }\n\n const selectionSet = transactions.some(transaction => transaction.selectionSet)\n\n if (!selectionSet || !oldState.selection.empty || !newState.selection.empty) {\n return\n }\n\n const detailsIsActive = isActive(newState, type.name)\n\n if (!detailsIsActive) {\n return\n }\n\n const { $from } = newState.selection\n const isVisible = isNodeVisible($from.pos, editor)\n\n if (isVisible) {\n return\n }\n\n const details = findClosestVisibleNode($from, node => node.type === type, editor)\n\n if (!details) {\n return\n }\n\n const detailsSummaries = findChildren(\n details.node,\n node => node.type === newState.schema.nodes.detailsSummary,\n )\n\n if (!detailsSummaries.length) {\n return\n }\n\n const detailsSummary = detailsSummaries[0]\n const selectionDirection = oldState.selection.from < newState.selection.from ? 'forward' : 'backward'\n const correctedPosition =\n selectionDirection === 'forward'\n ? details.start + detailsSummary.pos\n : details.pos + detailsSummary.pos + detailsSummary.node.nodeSize\n const selection = TextSelection.create(newState.doc, correctedPosition)\n const transaction = newState.tr.setSelection(selection)\n\n return transaction\n },\n }),\n ]\n },\n})\n","import type { Editor } from '@tiptap/core'\n\nexport const isNodeVisible = (position: number, editor: Editor): boolean => {\n const node = editor.view.domAtPos(position).node as HTMLElement\n const isOpen = node.offsetParent !== null\n\n return isOpen\n}\n","import type { Editor, Predicate } from '@tiptap/core'\nimport type { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const findClosestVisibleNode = (\n $pos: ResolvedPos,\n predicate: Predicate,\n editor: Editor,\n):\n | {\n pos: number\n start: number\n depth: number\n node: ProseMirrorNode\n }\n | undefined => {\n for (let i = $pos.depth; i > 0; i -= 1) {\n const node = $pos.node(i)\n const match = predicate(node)\n const isVisible = isNodeVisible($pos.start(i), editor)\n\n if (match && isVisible) {\n return {\n pos: i > 0 ? $pos.before(i) : 0,\n start: $pos.start(i),\n depth: i,\n node,\n }\n }\n }\n}\n","import type { Editor } from '@tiptap/core'\nimport { findChildren, findParentNode } from '@tiptap/core'\nimport { GapCursor } from '@tiptap/pm/gapcursor'\nimport type { ResolvedPos } from '@tiptap/pm/model'\nimport type { Selection } from '@tiptap/pm/state'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const setGapCursor = (editor: Editor, direction: 'down' | 'right') => {\n const { state, view, extensionManager } = editor\n const { schema, selection } = state\n const { empty, $anchor } = selection\n const hasGapCursorExtension = !!extensionManager.extensions.find(extension => extension.name === 'gapCursor')\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary || !hasGapCursorExtension) {\n return false\n }\n\n if (direction === 'right' && $anchor.parentOffset !== $anchor.parent.nodeSize - 2) {\n return false\n }\n\n const details = findParentNode(node => node.type === schema.nodes.details)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsContent = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsContent.length) {\n return false\n }\n\n const isOpen = isNodeVisible(details.start + detailsContent[0].pos + 1, editor)\n\n if (isOpen) {\n return false\n }\n\n const $position = state.doc.resolve(details.pos + details.node.nodeSize)\n const $validPosition = GapCursor.findFrom($position, 1, false) as unknown as null | ResolvedPos\n\n if (!$validPosition) {\n return false\n }\n\n const { tr } = state\n const gapCursorSelection = new GapCursor($validPosition) as Selection\n\n tr.setSelection(gapCursorSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n}\n","import { createBlockMarkdownSpec, defaultBlockAt, findParentNode, mergeAttributes, Node } from '@tiptap/core'\nimport { Selection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nexport interface DetailsContentOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsContent = Node.create<DetailsContentOptions>({\n name: 'detailsContent',\n\n content: 'block+',\n\n defining: true,\n\n selectable: false,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: `div[data-type=\"${this.name}\"]`,\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 'data-type': this.name }), 0]\n },\n\n addNodeView() {\n return ({ HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n hidden: 'hidden',\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n dom.addEventListener('toggleDetailsContent', () => {\n dom.toggleAttribute('hidden')\n })\n\n return {\n dom,\n contentDOM: dom,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n return true\n },\n }\n }\n },\n\n addKeyboardShortcuts() {\n return {\n // Escape node on double enter\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { selection } = state\n const { $from, empty } = selection\n const detailsContent = findParentNode(node => node.type === this.type)(selection)\n\n if (!empty || !detailsContent || !detailsContent.node.childCount) {\n return false\n }\n\n const fromIndex = $from.index(detailsContent.depth)\n const { childCount } = detailsContent.node\n const isAtEnd = childCount === fromIndex + 1\n\n if (!isAtEnd) {\n return false\n }\n\n const defaultChildType = detailsContent.node.type.contentMatch.defaultType\n const defaultChildNode = defaultChildType?.createAndFill()\n\n if (!defaultChildNode) {\n return false\n }\n\n const $childPos = state.doc.resolve(detailsContent.pos + 1)\n const lastChildIndex = childCount - 1\n const lastChildNode = detailsContent.node.child(lastChildIndex)\n const lastChildPos = $childPos.posAtIndex(lastChildIndex, detailsContent.depth)\n const lastChildNodeIsEmpty = lastChildNode.eq(defaultChildNode)\n\n if (!lastChildNodeIsEmpty) {\n return false\n }\n\n // get parent of details node\n const above = $from.node(-3)\n\n if (!above) {\n return false\n }\n\n // get default node type after details node\n const after = $from.indexAfter(-3)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const { tr } = state\n const pos = $from.after(-2)\n\n tr.replaceWith(pos, pos, node)\n\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n\n const deleteFrom = lastChildPos\n const deleteTo = lastChildPos + lastChildNode.nodeSize\n\n tr.delete(deleteFrom, deleteTo)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n }\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsContent',\n }),\n})\n","import { createBlockMarkdownSpec, mergeAttributes, Node } from '@tiptap/core'\n\nexport interface DetailsSummaryOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsSummary = Node.create<DetailsSummaryOptions>({\n name: 'detailsSummary',\n\n content: 'text*',\n\n defining: true,\n\n selectable: false,\n\n isolating: true,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'summary',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['summary', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsSummary',\n content: 'inline',\n }),\n})\n"],"mappings":"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","names":["import_core","transaction","import_core","import_state","node","import_core"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { Node } from '@tiptap/core';
|
|
2
|
+
import { Node as Node$1 } from '@tiptap/pm/model';
|
|
2
3
|
|
|
4
|
+
interface DetailsRenderToggleButtonOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The toggle button element rendered by the node view.
|
|
7
|
+
*/
|
|
8
|
+
element: HTMLButtonElement;
|
|
9
|
+
/**
|
|
10
|
+
* The current open state of the details node.
|
|
11
|
+
*/
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The current node used to derive toggle button state.
|
|
15
|
+
*/
|
|
16
|
+
node: Node$1;
|
|
17
|
+
}
|
|
3
18
|
interface DetailsOptions {
|
|
4
19
|
/**
|
|
5
20
|
* Specify if the open status should be saved in the document. Defaults to `false`.
|
|
@@ -15,6 +30,10 @@ interface DetailsOptions {
|
|
|
15
30
|
HTMLAttributes: {
|
|
16
31
|
[key: string]: any;
|
|
17
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Customizes the rendered toggle button.
|
|
35
|
+
*/
|
|
36
|
+
renderToggleButton: (options: DetailsRenderToggleButtonOptions) => void;
|
|
18
37
|
}
|
|
19
38
|
declare module '@tiptap/core' {
|
|
20
39
|
interface Commands<ReturnType> {
|
|
@@ -52,4 +71,4 @@ interface DetailsSummaryOptions {
|
|
|
52
71
|
}
|
|
53
72
|
declare const DetailsSummary: Node<DetailsSummaryOptions, any>;
|
|
54
73
|
|
|
55
|
-
export { Details, DetailsContent, type DetailsContentOptions, type DetailsOptions, DetailsSummary, type DetailsSummaryOptions, Details as default };
|
|
74
|
+
export { Details, DetailsContent, type DetailsContentOptions, type DetailsOptions, type DetailsRenderToggleButtonOptions, DetailsSummary, type DetailsSummaryOptions, Details as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { Node } from '@tiptap/core';
|
|
2
|
+
import { Node as Node$1 } from '@tiptap/pm/model';
|
|
2
3
|
|
|
4
|
+
interface DetailsRenderToggleButtonOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The toggle button element rendered by the node view.
|
|
7
|
+
*/
|
|
8
|
+
element: HTMLButtonElement;
|
|
9
|
+
/**
|
|
10
|
+
* The current open state of the details node.
|
|
11
|
+
*/
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The current node used to derive toggle button state.
|
|
15
|
+
*/
|
|
16
|
+
node: Node$1;
|
|
17
|
+
}
|
|
3
18
|
interface DetailsOptions {
|
|
4
19
|
/**
|
|
5
20
|
* Specify if the open status should be saved in the document. Defaults to `false`.
|
|
@@ -15,6 +30,10 @@ interface DetailsOptions {
|
|
|
15
30
|
HTMLAttributes: {
|
|
16
31
|
[key: string]: any;
|
|
17
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Customizes the rendered toggle button.
|
|
35
|
+
*/
|
|
36
|
+
renderToggleButton: (options: DetailsRenderToggleButtonOptions) => void;
|
|
18
37
|
}
|
|
19
38
|
declare module '@tiptap/core' {
|
|
20
39
|
interface Commands<ReturnType> {
|
|
@@ -52,4 +71,4 @@ interface DetailsSummaryOptions {
|
|
|
52
71
|
}
|
|
53
72
|
declare const DetailsSummary: Node<DetailsSummaryOptions, any>;
|
|
54
73
|
|
|
55
|
-
export { Details, DetailsContent, type DetailsContentOptions, type DetailsOptions, DetailsSummary, type DetailsSummaryOptions, Details as default };
|
|
74
|
+
export { Details, DetailsContent, type DetailsContentOptions, type DetailsOptions, type DetailsRenderToggleButtonOptions, DetailsSummary, type DetailsSummaryOptions, Details as default };
|
package/dist/index.js
CHANGED
|
@@ -86,7 +86,10 @@ var Details = Node.create({
|
|
|
86
86
|
return {
|
|
87
87
|
persist: false,
|
|
88
88
|
openClassName: "is-open",
|
|
89
|
-
HTMLAttributes: {}
|
|
89
|
+
HTMLAttributes: {},
|
|
90
|
+
renderToggleButton: ({ element, isOpen }) => {
|
|
91
|
+
element.setAttribute("aria-label", isOpen ? "Collapse details content" : "Expand details content");
|
|
92
|
+
}
|
|
90
93
|
};
|
|
91
94
|
},
|
|
92
95
|
addAttributes() {
|
|
@@ -129,10 +132,17 @@ var Details = Node.create({
|
|
|
129
132
|
Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value));
|
|
130
133
|
const toggle = document.createElement("button");
|
|
131
134
|
toggle.type = "button";
|
|
135
|
+
const renderToggleButton = (options) => {
|
|
136
|
+
this.options.renderToggleButton({
|
|
137
|
+
element: toggle,
|
|
138
|
+
...options
|
|
139
|
+
});
|
|
140
|
+
};
|
|
132
141
|
dom.append(toggle);
|
|
133
142
|
const content = document.createElement("div");
|
|
134
143
|
dom.append(content);
|
|
135
|
-
const toggleDetailsContent = (
|
|
144
|
+
const toggleDetailsContent = (options) => {
|
|
145
|
+
const { setToValue, node: currentNode = node } = options || {};
|
|
136
146
|
if (setToValue !== void 0) {
|
|
137
147
|
if (setToValue) {
|
|
138
148
|
if (dom.classList.contains(this.options.openClassName)) {
|
|
@@ -148,10 +158,19 @@ var Details = Node.create({
|
|
|
148
158
|
} else {
|
|
149
159
|
dom.classList.toggle(this.options.openClassName);
|
|
150
160
|
}
|
|
161
|
+
const isOpen = dom.classList.contains(this.options.openClassName);
|
|
162
|
+
renderToggleButton({
|
|
163
|
+
isOpen,
|
|
164
|
+
node: currentNode
|
|
165
|
+
});
|
|
151
166
|
const event = new Event("toggleDetailsContent");
|
|
152
167
|
const detailsContent = content.querySelector(':scope > div[data-type="detailsContent"]');
|
|
153
168
|
detailsContent == null ? void 0 : detailsContent.dispatchEvent(event);
|
|
154
169
|
};
|
|
170
|
+
renderToggleButton({
|
|
171
|
+
isOpen: Boolean(node.attrs.open),
|
|
172
|
+
node
|
|
173
|
+
});
|
|
155
174
|
if (node.attrs.open) {
|
|
156
175
|
setTimeout(() => toggleDetailsContent());
|
|
157
176
|
}
|
|
@@ -189,14 +208,25 @@ var Details = Node.create({
|
|
|
189
208
|
if (mutation.type === "selection") {
|
|
190
209
|
return false;
|
|
191
210
|
}
|
|
192
|
-
|
|
211
|
+
const target = mutation.target;
|
|
212
|
+
const isInsideWrapper = dom.contains(target);
|
|
213
|
+
const isInsideToggleButton = toggle.contains(target);
|
|
214
|
+
return isInsideToggleButton || !isInsideWrapper || dom === target;
|
|
193
215
|
},
|
|
194
216
|
update: (updatedNode) => {
|
|
195
217
|
if (updatedNode.type !== this.type) {
|
|
196
218
|
return false;
|
|
197
219
|
}
|
|
198
220
|
if (updatedNode.attrs.open !== void 0) {
|
|
199
|
-
toggleDetailsContent(
|
|
221
|
+
toggleDetailsContent({
|
|
222
|
+
setToValue: updatedNode.attrs.open,
|
|
223
|
+
node: updatedNode
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
renderToggleButton({
|
|
227
|
+
isOpen: dom.classList.contains(this.options.openClassName),
|
|
228
|
+
node: updatedNode
|
|
229
|
+
});
|
|
200
230
|
}
|
|
201
231
|
return true;
|
|
202
232
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/details.ts","../src/helpers/isNodeVisible.ts","../src/helpers/findClosestVisibleNode.ts","../src/helpers/setGapCursor.ts","../src/content/details-content.ts","../src/summary/details-summary.ts","../src/index.ts"],"sourcesContent":["import {\n createBlockMarkdownSpec,\n defaultBlockAt,\n findChildren,\n findParentNode,\n isActive,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { findClosestVisibleNode } from './helpers/findClosestVisibleNode.js'\nimport { isNodeVisible } from './helpers/isNodeVisible.js'\nimport { setGapCursor } from './helpers/setGapCursor.js'\n\nexport interface DetailsOptions {\n /**\n * Specify if the open status should be saved in the document. Defaults to `false`.\n */\n persist: boolean\n /**\n * Specifies a CSS class that is set when toggling the content. Defaults to `is-open`.\n */\n openClassName: string\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n details: {\n /**\n * Set a details node\n */\n setDetails: () => ReturnType\n /**\n * Unset a details node\n */\n unsetDetails: () => ReturnType\n }\n }\n}\n\nexport const Details = Node.create<DetailsOptions>({\n name: 'details',\n\n content: 'detailsSummary detailsContent',\n\n group: 'block',\n\n defining: true,\n\n isolating: true,\n\n // @ts-ignore reason: `allowGapCursor` is not a valid property by default, but the `GapCursor` extension adds it to the Nodeconfig type\n allowGapCursor: false,\n\n addOptions() {\n return {\n persist: false,\n openClassName: 'is-open',\n HTMLAttributes: {},\n }\n },\n\n addAttributes() {\n if (!this.options.persist) {\n return []\n }\n\n return {\n open: {\n default: false,\n parseHTML: element => element.hasAttribute('open'),\n renderHTML: ({ open }) => {\n if (!open) {\n return {}\n }\n\n return { open: '' }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'details',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['details', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'details',\n content: 'block',\n }),\n\n addNodeView() {\n return ({ editor, getPos, node, HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n const toggle = document.createElement('button')\n\n toggle.type = 'button'\n\n dom.append(toggle)\n\n const content = document.createElement('div')\n\n dom.append(content)\n\n const toggleDetailsContent = (setToValue?: boolean) => {\n if (setToValue !== undefined) {\n if (setToValue) {\n if (dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.add(this.options.openClassName)\n } else {\n if (!dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.remove(this.options.openClassName)\n }\n } else {\n dom.classList.toggle(this.options.openClassName)\n }\n\n const event = new Event('toggleDetailsContent')\n const detailsContent = content.querySelector(':scope > div[data-type=\"detailsContent\"]')\n\n detailsContent?.dispatchEvent(event)\n }\n\n if (node.attrs.open) {\n setTimeout(() => toggleDetailsContent())\n }\n\n toggle.addEventListener('click', () => {\n toggleDetailsContent()\n\n if (!this.options.persist) {\n editor.commands.focus(undefined, { scrollIntoView: false })\n\n return\n }\n\n if (editor.isEditable && typeof getPos === 'function') {\n const { from, to } = editor.state.selection\n\n editor\n .chain()\n .command(({ tr }) => {\n const pos = getPos()\n\n if (!pos) {\n return false\n }\n\n const currentNode = tr.doc.nodeAt(pos)\n\n if (currentNode?.type !== this.type) {\n return false\n }\n\n tr.setNodeMarkup(pos, undefined, {\n open: !currentNode.attrs.open,\n })\n\n return true\n })\n .setTextSelection({\n from,\n to,\n })\n .focus(undefined, { scrollIntoView: false })\n .run()\n }\n })\n\n return {\n dom,\n contentDOM: content,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n // Only update the open state if set\n if (updatedNode.attrs.open !== undefined) {\n toggleDetailsContent(updatedNode.attrs.open)\n }\n\n return true\n },\n }\n }\n },\n\n addCommands() {\n return {\n setDetails:\n () =>\n ({ state, chain }) => {\n const { schema, selection } = state\n const { $from, $to } = selection\n const range = $from.blockRange($to)\n\n if (!range) {\n return false\n }\n\n const slice = state.doc.slice(range.start, range.end)\n const match = schema.nodes.detailsContent.contentMatch.matchFragment(slice.content)\n\n if (!match) {\n return false\n }\n\n const content = slice.toJSON()?.content || []\n\n return chain()\n .insertContentAt(\n { from: range.start, to: range.end },\n {\n type: this.name,\n content: [\n {\n type: 'detailsSummary',\n },\n {\n type: 'detailsContent',\n content,\n },\n ],\n },\n )\n .setTextSelection(range.start + 2)\n .run()\n },\n\n unsetDetails:\n () =>\n ({ state, chain }) => {\n const { selection, schema } = state\n const details = findParentNode(node => node.type === this.type)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsSummaries = findChildren(details.node, node => node.type === schema.nodes.detailsSummary)\n const detailsContents = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsSummaries.length || !detailsContents.length) {\n return false\n }\n\n const detailsSummary = detailsSummaries[0]\n const detailsContent = detailsContents[0]\n const from = details.pos\n const $from = state.doc.resolve(from)\n const to = from + details.node.nodeSize\n const range = { from, to }\n const content = (detailsContent.node.content.toJSON() as []) || []\n const defaultTypeForSummary = $from.parent.type.contentMatch.defaultType\n\n // TODO: this may break for some custom schemas\n const summaryContent = defaultTypeForSummary?.create(null, detailsSummary.node.content).toJSON()\n const mergedContent = [summaryContent, ...content]\n\n return chain()\n .insertContentAt(range, mergedContent)\n .setTextSelection(from + 1)\n .run()\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { schema, selection } = this.editor.state\n const { empty, $anchor } = selection\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n // for some reason safari removes the whole text content within a `<summary>`tag on backspace\n // so we have to remove the text manually\n // see: https://discuss.prosemirror.net/t/safari-backspace-bug-with-details-tag/4223\n if ($anchor.parentOffset !== 0) {\n return this.editor.commands.command(({ tr }) => {\n const from = $anchor.pos - 1\n const to = $anchor.pos\n\n tr.delete(from, to)\n\n return true\n })\n }\n\n return this.editor.commands.unsetDetails()\n },\n\n // Creates a new node below it if it is closed.\n // Otherwise inside `DetailsContent`.\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { schema, selection } = state\n const { $head } = selection\n\n if ($head.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n const isVisible = isNodeVisible($head.after() + 1, editor)\n const above = isVisible ? state.doc.nodeAt($head.after()) : $head.node(-2)\n\n if (!above) {\n return false\n }\n\n const after = isVisible ? 0 : $head.indexAfter(-1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const pos = isVisible ? $head.after() + 1 : $head.after(-1)\n const tr = state.tr.replaceWith(pos, pos, node)\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowRight: ({ editor }) => {\n return setGapCursor(editor, 'right')\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowDown: ({ editor }) => {\n return setGapCursor(editor, 'down')\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [\n // This plugin prevents text selections within the hidden content in `DetailsContent`.\n // The cursor is moved to the next visible position.\n new Plugin({\n key: new PluginKey('detailsSelection'),\n appendTransaction: (transactions, oldState, newState) => {\n const { editor, type } = this\n const isComposing = editor.view.composing\n\n if (isComposing) {\n return\n }\n\n const selectionSet = transactions.some(transaction => transaction.selectionSet)\n\n if (!selectionSet || !oldState.selection.empty || !newState.selection.empty) {\n return\n }\n\n const detailsIsActive = isActive(newState, type.name)\n\n if (!detailsIsActive) {\n return\n }\n\n const { $from } = newState.selection\n const isVisible = isNodeVisible($from.pos, editor)\n\n if (isVisible) {\n return\n }\n\n const details = findClosestVisibleNode($from, node => node.type === type, editor)\n\n if (!details) {\n return\n }\n\n const detailsSummaries = findChildren(\n details.node,\n node => node.type === newState.schema.nodes.detailsSummary,\n )\n\n if (!detailsSummaries.length) {\n return\n }\n\n const detailsSummary = detailsSummaries[0]\n const selectionDirection = oldState.selection.from < newState.selection.from ? 'forward' : 'backward'\n const correctedPosition =\n selectionDirection === 'forward'\n ? details.start + detailsSummary.pos\n : details.pos + detailsSummary.pos + detailsSummary.node.nodeSize\n const selection = TextSelection.create(newState.doc, correctedPosition)\n const transaction = newState.tr.setSelection(selection)\n\n return transaction\n },\n }),\n ]\n },\n})\n","import type { Editor } from '@tiptap/core'\n\nexport const isNodeVisible = (position: number, editor: Editor): boolean => {\n const node = editor.view.domAtPos(position).node as HTMLElement\n const isOpen = node.offsetParent !== null\n\n return isOpen\n}\n","import type { Editor, Predicate } from '@tiptap/core'\nimport type { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const findClosestVisibleNode = (\n $pos: ResolvedPos,\n predicate: Predicate,\n editor: Editor,\n):\n | {\n pos: number\n start: number\n depth: number\n node: ProseMirrorNode\n }\n | undefined => {\n for (let i = $pos.depth; i > 0; i -= 1) {\n const node = $pos.node(i)\n const match = predicate(node)\n const isVisible = isNodeVisible($pos.start(i), editor)\n\n if (match && isVisible) {\n return {\n pos: i > 0 ? $pos.before(i) : 0,\n start: $pos.start(i),\n depth: i,\n node,\n }\n }\n }\n}\n","import type { Editor } from '@tiptap/core'\nimport { findChildren, findParentNode } from '@tiptap/core'\nimport { GapCursor } from '@tiptap/pm/gapcursor'\nimport type { ResolvedPos } from '@tiptap/pm/model'\nimport type { Selection } from '@tiptap/pm/state'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const setGapCursor = (editor: Editor, direction: 'down' | 'right') => {\n const { state, view, extensionManager } = editor\n const { schema, selection } = state\n const { empty, $anchor } = selection\n const hasGapCursorExtension = !!extensionManager.extensions.find(extension => extension.name === 'gapCursor')\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary || !hasGapCursorExtension) {\n return false\n }\n\n if (direction === 'right' && $anchor.parentOffset !== $anchor.parent.nodeSize - 2) {\n return false\n }\n\n const details = findParentNode(node => node.type === schema.nodes.details)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsContent = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsContent.length) {\n return false\n }\n\n const isOpen = isNodeVisible(details.start + detailsContent[0].pos + 1, editor)\n\n if (isOpen) {\n return false\n }\n\n const $position = state.doc.resolve(details.pos + details.node.nodeSize)\n const $validPosition = GapCursor.findFrom($position, 1, false) as unknown as null | ResolvedPos\n\n if (!$validPosition) {\n return false\n }\n\n const { tr } = state\n const gapCursorSelection = new GapCursor($validPosition) as Selection\n\n tr.setSelection(gapCursorSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n}\n","import { createBlockMarkdownSpec, defaultBlockAt, findParentNode, mergeAttributes, Node } from '@tiptap/core'\nimport { Selection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nexport interface DetailsContentOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsContent = Node.create<DetailsContentOptions>({\n name: 'detailsContent',\n\n content: 'block+',\n\n defining: true,\n\n selectable: false,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: `div[data-type=\"${this.name}\"]`,\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 'data-type': this.name }), 0]\n },\n\n addNodeView() {\n return ({ HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n hidden: 'hidden',\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n dom.addEventListener('toggleDetailsContent', () => {\n dom.toggleAttribute('hidden')\n })\n\n return {\n dom,\n contentDOM: dom,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n return true\n },\n }\n }\n },\n\n addKeyboardShortcuts() {\n return {\n // Escape node on double enter\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { selection } = state\n const { $from, empty } = selection\n const detailsContent = findParentNode(node => node.type === this.type)(selection)\n\n if (!empty || !detailsContent || !detailsContent.node.childCount) {\n return false\n }\n\n const fromIndex = $from.index(detailsContent.depth)\n const { childCount } = detailsContent.node\n const isAtEnd = childCount === fromIndex + 1\n\n if (!isAtEnd) {\n return false\n }\n\n const defaultChildType = detailsContent.node.type.contentMatch.defaultType\n const defaultChildNode = defaultChildType?.createAndFill()\n\n if (!defaultChildNode) {\n return false\n }\n\n const $childPos = state.doc.resolve(detailsContent.pos + 1)\n const lastChildIndex = childCount - 1\n const lastChildNode = detailsContent.node.child(lastChildIndex)\n const lastChildPos = $childPos.posAtIndex(lastChildIndex, detailsContent.depth)\n const lastChildNodeIsEmpty = lastChildNode.eq(defaultChildNode)\n\n if (!lastChildNodeIsEmpty) {\n return false\n }\n\n // get parent of details node\n const above = $from.node(-3)\n\n if (!above) {\n return false\n }\n\n // get default node type after details node\n const after = $from.indexAfter(-3)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const { tr } = state\n const pos = $from.after(-2)\n\n tr.replaceWith(pos, pos, node)\n\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n\n const deleteFrom = lastChildPos\n const deleteTo = lastChildPos + lastChildNode.nodeSize\n\n tr.delete(deleteFrom, deleteTo)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n }\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsContent',\n }),\n})\n","import { createBlockMarkdownSpec, mergeAttributes, Node } from '@tiptap/core'\n\nexport interface DetailsSummaryOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsSummary = Node.create<DetailsSummaryOptions>({\n name: 'detailsSummary',\n\n content: 'text*',\n\n defining: true,\n\n selectable: false,\n\n isolating: true,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'summary',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['summary', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsSummary',\n content: 'inline',\n }),\n})\n","import { Details } from './details.js'\n\nexport * from './content/index.js'\nexport * from './details.js'\nexport * from './summary/index.js'\n\nexport default Details\n"],"mappings":"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","names":["findChildren","findParentNode","findParentNode","findChildren","transaction","createBlockMarkdownSpec","defaultBlockAt","findParentNode","mergeAttributes","Node","Selection","node","createBlockMarkdownSpec","mergeAttributes","Node"]}
|
|
1
|
+
{"version":3,"sources":["../src/details.ts","../src/helpers/isNodeVisible.ts","../src/helpers/findClosestVisibleNode.ts","../src/helpers/setGapCursor.ts","../src/content/details-content.ts","../src/summary/details-summary.ts","../src/index.ts"],"sourcesContent":["import {\n createBlockMarkdownSpec,\n defaultBlockAt,\n findChildren,\n findParentNode,\n isActive,\n mergeAttributes,\n Node,\n} from '@tiptap/core'\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nimport { findClosestVisibleNode } from './helpers/findClosestVisibleNode.js'\nimport { isNodeVisible } from './helpers/isNodeVisible.js'\nimport { setGapCursor } from './helpers/setGapCursor.js'\n\nexport interface DetailsRenderToggleButtonOptions {\n /**\n * The toggle button element rendered by the node view.\n */\n element: HTMLButtonElement\n /**\n * The current open state of the details node.\n */\n isOpen: boolean\n /**\n * The current node used to derive toggle button state.\n */\n node: ProseMirrorNode\n}\n\nexport interface DetailsOptions {\n /**\n * Specify if the open status should be saved in the document. Defaults to `false`.\n */\n persist: boolean\n /**\n * Specifies a CSS class that is set when toggling the content. Defaults to `is-open`.\n */\n openClassName: string\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n /**\n * Customizes the rendered toggle button.\n */\n renderToggleButton: (options: DetailsRenderToggleButtonOptions) => void\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n details: {\n /**\n * Set a details node\n */\n setDetails: () => ReturnType\n /**\n * Unset a details node\n */\n unsetDetails: () => ReturnType\n }\n }\n}\n\nexport const Details = Node.create<DetailsOptions>({\n name: 'details',\n\n content: 'detailsSummary detailsContent',\n\n group: 'block',\n\n defining: true,\n\n isolating: true,\n\n // @ts-ignore reason: `allowGapCursor` is not a valid property by default, but the `GapCursor` extension adds it to the Nodeconfig type\n allowGapCursor: false,\n\n addOptions() {\n return {\n persist: false,\n openClassName: 'is-open',\n HTMLAttributes: {},\n renderToggleButton: ({ element, isOpen }) => {\n element.setAttribute('aria-label', isOpen ? 'Collapse details content' : 'Expand details content')\n },\n }\n },\n\n addAttributes() {\n if (!this.options.persist) {\n return []\n }\n\n return {\n open: {\n default: false,\n parseHTML: element => element.hasAttribute('open'),\n renderHTML: ({ open }) => {\n if (!open) {\n return {}\n }\n\n return { open: '' }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'details',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['details', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'details',\n content: 'block',\n }),\n\n addNodeView() {\n return ({ editor, getPos, node, HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n const toggle = document.createElement('button')\n\n toggle.type = 'button'\n\n const renderToggleButton = (options: Omit<DetailsRenderToggleButtonOptions, 'element'>) => {\n this.options.renderToggleButton({\n element: toggle,\n ...options,\n })\n }\n\n dom.append(toggle)\n\n const content = document.createElement('div')\n\n dom.append(content)\n\n const toggleDetailsContent = (options?: { setToValue?: boolean; node?: ProseMirrorNode }) => {\n const { setToValue, node: currentNode = node } = options || {}\n\n if (setToValue !== undefined) {\n if (setToValue) {\n if (dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.add(this.options.openClassName)\n } else {\n if (!dom.classList.contains(this.options.openClassName)) {\n return\n }\n dom.classList.remove(this.options.openClassName)\n }\n } else {\n dom.classList.toggle(this.options.openClassName)\n }\n\n const isOpen = dom.classList.contains(this.options.openClassName)\n\n renderToggleButton({\n isOpen,\n node: currentNode,\n })\n\n const event = new Event('toggleDetailsContent')\n const detailsContent = content.querySelector(':scope > div[data-type=\"detailsContent\"]')\n\n detailsContent?.dispatchEvent(event)\n }\n\n renderToggleButton({\n isOpen: Boolean(node.attrs.open),\n node,\n })\n\n if (node.attrs.open) {\n setTimeout(() => toggleDetailsContent())\n }\n\n toggle.addEventListener('click', () => {\n toggleDetailsContent()\n\n if (!this.options.persist) {\n editor.commands.focus(undefined, { scrollIntoView: false })\n\n return\n }\n\n if (editor.isEditable && typeof getPos === 'function') {\n const { from, to } = editor.state.selection\n\n editor\n .chain()\n .command(({ tr }) => {\n const pos = getPos()\n\n if (!pos) {\n return false\n }\n\n const currentNode = tr.doc.nodeAt(pos)\n\n if (currentNode?.type !== this.type) {\n return false\n }\n\n tr.setNodeMarkup(pos, undefined, {\n open: !currentNode.attrs.open,\n })\n\n return true\n })\n .setTextSelection({\n from,\n to,\n })\n .focus(undefined, { scrollIntoView: false })\n .run()\n }\n })\n\n return {\n dom,\n contentDOM: content,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n const target = mutation.target\n const isInsideWrapper = dom.contains(target)\n const isInsideToggleButton = toggle.contains(target)\n\n return isInsideToggleButton || !isInsideWrapper || dom === target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n // Only update the open state if set\n if (updatedNode.attrs.open !== undefined) {\n toggleDetailsContent({\n setToValue: updatedNode.attrs.open,\n node: updatedNode,\n })\n } else {\n renderToggleButton({\n isOpen: dom.classList.contains(this.options.openClassName),\n node: updatedNode,\n })\n }\n\n return true\n },\n }\n }\n },\n\n addCommands() {\n return {\n setDetails:\n () =>\n ({ state, chain }) => {\n const { schema, selection } = state\n const { $from, $to } = selection\n const range = $from.blockRange($to)\n\n if (!range) {\n return false\n }\n\n const slice = state.doc.slice(range.start, range.end)\n const match = schema.nodes.detailsContent.contentMatch.matchFragment(slice.content)\n\n if (!match) {\n return false\n }\n\n const content = slice.toJSON()?.content || []\n\n return chain()\n .insertContentAt(\n { from: range.start, to: range.end },\n {\n type: this.name,\n content: [\n {\n type: 'detailsSummary',\n },\n {\n type: 'detailsContent',\n content,\n },\n ],\n },\n )\n .setTextSelection(range.start + 2)\n .run()\n },\n\n unsetDetails:\n () =>\n ({ state, chain }) => {\n const { selection, schema } = state\n const details = findParentNode(node => node.type === this.type)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsSummaries = findChildren(details.node, node => node.type === schema.nodes.detailsSummary)\n const detailsContents = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsSummaries.length || !detailsContents.length) {\n return false\n }\n\n const detailsSummary = detailsSummaries[0]\n const detailsContent = detailsContents[0]\n const from = details.pos\n const $from = state.doc.resolve(from)\n const to = from + details.node.nodeSize\n const range = { from, to }\n const content = (detailsContent.node.content.toJSON() as []) || []\n const defaultTypeForSummary = $from.parent.type.contentMatch.defaultType\n\n // TODO: this may break for some custom schemas\n const summaryContent = defaultTypeForSummary?.create(null, detailsSummary.node.content).toJSON()\n const mergedContent = [summaryContent, ...content]\n\n return chain()\n .insertContentAt(range, mergedContent)\n .setTextSelection(from + 1)\n .run()\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { schema, selection } = this.editor.state\n const { empty, $anchor } = selection\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n // for some reason safari removes the whole text content within a `<summary>`tag on backspace\n // so we have to remove the text manually\n // see: https://discuss.prosemirror.net/t/safari-backspace-bug-with-details-tag/4223\n if ($anchor.parentOffset !== 0) {\n return this.editor.commands.command(({ tr }) => {\n const from = $anchor.pos - 1\n const to = $anchor.pos\n\n tr.delete(from, to)\n\n return true\n })\n }\n\n return this.editor.commands.unsetDetails()\n },\n\n // Creates a new node below it if it is closed.\n // Otherwise inside `DetailsContent`.\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { schema, selection } = state\n const { $head } = selection\n\n if ($head.parent.type !== schema.nodes.detailsSummary) {\n return false\n }\n\n const isVisible = isNodeVisible($head.after() + 1, editor)\n const above = isVisible ? state.doc.nodeAt($head.after()) : $head.node(-2)\n\n if (!above) {\n return false\n }\n\n const after = isVisible ? 0 : $head.indexAfter(-1)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const pos = isVisible ? $head.after() + 1 : $head.after(-1)\n const tr = state.tr.replaceWith(pos, pos, node)\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowRight: ({ editor }) => {\n return setGapCursor(editor, 'right')\n },\n\n // The default gapcursor implementation can’t handle hidden content, so we need to fix this.\n ArrowDown: ({ editor }) => {\n return setGapCursor(editor, 'down')\n },\n }\n },\n\n addProseMirrorPlugins() {\n return [\n // This plugin prevents text selections within the hidden content in `DetailsContent`.\n // The cursor is moved to the next visible position.\n new Plugin({\n key: new PluginKey('detailsSelection'),\n appendTransaction: (transactions, oldState, newState) => {\n const { editor, type } = this\n const isComposing = editor.view.composing\n\n if (isComposing) {\n return\n }\n\n const selectionSet = transactions.some(transaction => transaction.selectionSet)\n\n if (!selectionSet || !oldState.selection.empty || !newState.selection.empty) {\n return\n }\n\n const detailsIsActive = isActive(newState, type.name)\n\n if (!detailsIsActive) {\n return\n }\n\n const { $from } = newState.selection\n const isVisible = isNodeVisible($from.pos, editor)\n\n if (isVisible) {\n return\n }\n\n const details = findClosestVisibleNode($from, node => node.type === type, editor)\n\n if (!details) {\n return\n }\n\n const detailsSummaries = findChildren(\n details.node,\n node => node.type === newState.schema.nodes.detailsSummary,\n )\n\n if (!detailsSummaries.length) {\n return\n }\n\n const detailsSummary = detailsSummaries[0]\n const selectionDirection = oldState.selection.from < newState.selection.from ? 'forward' : 'backward'\n const correctedPosition =\n selectionDirection === 'forward'\n ? details.start + detailsSummary.pos\n : details.pos + detailsSummary.pos + detailsSummary.node.nodeSize\n const selection = TextSelection.create(newState.doc, correctedPosition)\n const transaction = newState.tr.setSelection(selection)\n\n return transaction\n },\n }),\n ]\n },\n})\n","import type { Editor } from '@tiptap/core'\n\nexport const isNodeVisible = (position: number, editor: Editor): boolean => {\n const node = editor.view.domAtPos(position).node as HTMLElement\n const isOpen = node.offsetParent !== null\n\n return isOpen\n}\n","import type { Editor, Predicate } from '@tiptap/core'\nimport type { Node as ProseMirrorNode, ResolvedPos } from '@tiptap/pm/model'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const findClosestVisibleNode = (\n $pos: ResolvedPos,\n predicate: Predicate,\n editor: Editor,\n):\n | {\n pos: number\n start: number\n depth: number\n node: ProseMirrorNode\n }\n | undefined => {\n for (let i = $pos.depth; i > 0; i -= 1) {\n const node = $pos.node(i)\n const match = predicate(node)\n const isVisible = isNodeVisible($pos.start(i), editor)\n\n if (match && isVisible) {\n return {\n pos: i > 0 ? $pos.before(i) : 0,\n start: $pos.start(i),\n depth: i,\n node,\n }\n }\n }\n}\n","import type { Editor } from '@tiptap/core'\nimport { findChildren, findParentNode } from '@tiptap/core'\nimport { GapCursor } from '@tiptap/pm/gapcursor'\nimport type { ResolvedPos } from '@tiptap/pm/model'\nimport type { Selection } from '@tiptap/pm/state'\n\nimport { isNodeVisible } from './isNodeVisible.js'\n\nexport const setGapCursor = (editor: Editor, direction: 'down' | 'right') => {\n const { state, view, extensionManager } = editor\n const { schema, selection } = state\n const { empty, $anchor } = selection\n const hasGapCursorExtension = !!extensionManager.extensions.find(extension => extension.name === 'gapCursor')\n\n if (!empty || $anchor.parent.type !== schema.nodes.detailsSummary || !hasGapCursorExtension) {\n return false\n }\n\n if (direction === 'right' && $anchor.parentOffset !== $anchor.parent.nodeSize - 2) {\n return false\n }\n\n const details = findParentNode(node => node.type === schema.nodes.details)(selection)\n\n if (!details) {\n return false\n }\n\n const detailsContent = findChildren(details.node, node => node.type === schema.nodes.detailsContent)\n\n if (!detailsContent.length) {\n return false\n }\n\n const isOpen = isNodeVisible(details.start + detailsContent[0].pos + 1, editor)\n\n if (isOpen) {\n return false\n }\n\n const $position = state.doc.resolve(details.pos + details.node.nodeSize)\n const $validPosition = GapCursor.findFrom($position, 1, false) as unknown as null | ResolvedPos\n\n if (!$validPosition) {\n return false\n }\n\n const { tr } = state\n const gapCursorSelection = new GapCursor($validPosition) as Selection\n\n tr.setSelection(gapCursorSelection)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n}\n","import { createBlockMarkdownSpec, defaultBlockAt, findParentNode, mergeAttributes, Node } from '@tiptap/core'\nimport { Selection } from '@tiptap/pm/state'\nimport type { ViewMutationRecord } from '@tiptap/pm/view'\n\nexport interface DetailsContentOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsContent = Node.create<DetailsContentOptions>({\n name: 'detailsContent',\n\n content: 'block+',\n\n defining: true,\n\n selectable: false,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: `div[data-type=\"${this.name}\"]`,\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 'data-type': this.name }), 0]\n },\n\n addNodeView() {\n return ({ HTMLAttributes }) => {\n const dom = document.createElement('div')\n const attributes = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': this.name,\n hidden: 'hidden',\n })\n\n Object.entries(attributes).forEach(([key, value]) => dom.setAttribute(key, value))\n\n dom.addEventListener('toggleDetailsContent', () => {\n dom.toggleAttribute('hidden')\n })\n\n return {\n dom,\n contentDOM: dom,\n ignoreMutation(mutation: ViewMutationRecord) {\n if (mutation.type === 'selection') {\n return false\n }\n\n return !dom.contains(mutation.target) || dom === mutation.target\n },\n update: updatedNode => {\n if (updatedNode.type !== this.type) {\n return false\n }\n\n return true\n },\n }\n }\n },\n\n addKeyboardShortcuts() {\n return {\n // Escape node on double enter\n Enter: ({ editor }) => {\n const { state, view } = editor\n const { selection } = state\n const { $from, empty } = selection\n const detailsContent = findParentNode(node => node.type === this.type)(selection)\n\n if (!empty || !detailsContent || !detailsContent.node.childCount) {\n return false\n }\n\n const fromIndex = $from.index(detailsContent.depth)\n const { childCount } = detailsContent.node\n const isAtEnd = childCount === fromIndex + 1\n\n if (!isAtEnd) {\n return false\n }\n\n const defaultChildType = detailsContent.node.type.contentMatch.defaultType\n const defaultChildNode = defaultChildType?.createAndFill()\n\n if (!defaultChildNode) {\n return false\n }\n\n const $childPos = state.doc.resolve(detailsContent.pos + 1)\n const lastChildIndex = childCount - 1\n const lastChildNode = detailsContent.node.child(lastChildIndex)\n const lastChildPos = $childPos.posAtIndex(lastChildIndex, detailsContent.depth)\n const lastChildNodeIsEmpty = lastChildNode.eq(defaultChildNode)\n\n if (!lastChildNodeIsEmpty) {\n return false\n }\n\n // get parent of details node\n const above = $from.node(-3)\n\n if (!above) {\n return false\n }\n\n // get default node type after details node\n const after = $from.indexAfter(-3)\n const type = defaultBlockAt(above.contentMatchAt(after))\n\n if (!type || !above.canReplaceWith(after, after, type)) {\n return false\n }\n\n const node = type.createAndFill()\n\n if (!node) {\n return false\n }\n\n const { tr } = state\n const pos = $from.after(-2)\n\n tr.replaceWith(pos, pos, node)\n\n const $pos = tr.doc.resolve(pos)\n const newSelection = Selection.near($pos, 1)\n\n tr.setSelection(newSelection)\n\n const deleteFrom = lastChildPos\n const deleteTo = lastChildPos + lastChildNode.nodeSize\n\n tr.delete(deleteFrom, deleteTo)\n tr.scrollIntoView()\n view.dispatch(tr)\n\n return true\n },\n }\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsContent',\n }),\n})\n","import { createBlockMarkdownSpec, mergeAttributes, Node } from '@tiptap/core'\n\nexport interface DetailsSummaryOptions {\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n */\n HTMLAttributes: {\n [key: string]: any\n }\n}\n\nexport const DetailsSummary = Node.create<DetailsSummaryOptions>({\n name: 'detailsSummary',\n\n content: 'text*',\n\n defining: true,\n\n selectable: false,\n\n isolating: true,\n\n addOptions() {\n return {\n HTMLAttributes: {},\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'summary',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['summary', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]\n },\n\n ...createBlockMarkdownSpec({\n nodeName: 'detailsSummary',\n content: 'inline',\n }),\n})\n","import { Details } from './details.js'\n\nexport * from './content/index.js'\nexport * from './details.js'\nexport * from './summary/index.js'\n\nexport default Details\n"],"mappings":"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","names":["findChildren","findParentNode","findParentNode","findChildren","transaction","createBlockMarkdownSpec","defaultBlockAt","findParentNode","mergeAttributes","Node","Selection","node","createBlockMarkdownSpec","mergeAttributes","Node"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiptap/extension-details",
|
|
3
3
|
"description": "details extension for tiptap",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.22.0",
|
|
5
5
|
"homepage": "https://tiptap.dev/api/nodes/details",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"tiptap",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@tiptap/core": "^3.
|
|
35
|
-
"@tiptap/extension-text-style": "^3.
|
|
36
|
-
"@tiptap/pm": "^3.
|
|
34
|
+
"@tiptap/core": "^3.22.0",
|
|
35
|
+
"@tiptap/extension-text-style": "^3.22.0",
|
|
36
|
+
"@tiptap/pm": "^3.22.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@tiptap/core": "^3.
|
|
40
|
-
"@tiptap/extension-text-style": "^3.
|
|
41
|
-
"@tiptap/pm": "^3.
|
|
39
|
+
"@tiptap/core": "^3.22.0",
|
|
40
|
+
"@tiptap/extension-text-style": "^3.22.0",
|
|
41
|
+
"@tiptap/pm": "^3.22.0"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|
package/src/details.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
mergeAttributes,
|
|
8
8
|
Node,
|
|
9
9
|
} from '@tiptap/core'
|
|
10
|
+
import type { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
10
11
|
import { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'
|
|
11
12
|
import type { ViewMutationRecord } from '@tiptap/pm/view'
|
|
12
13
|
|
|
@@ -14,6 +15,21 @@ import { findClosestVisibleNode } from './helpers/findClosestVisibleNode.js'
|
|
|
14
15
|
import { isNodeVisible } from './helpers/isNodeVisible.js'
|
|
15
16
|
import { setGapCursor } from './helpers/setGapCursor.js'
|
|
16
17
|
|
|
18
|
+
export interface DetailsRenderToggleButtonOptions {
|
|
19
|
+
/**
|
|
20
|
+
* The toggle button element rendered by the node view.
|
|
21
|
+
*/
|
|
22
|
+
element: HTMLButtonElement
|
|
23
|
+
/**
|
|
24
|
+
* The current open state of the details node.
|
|
25
|
+
*/
|
|
26
|
+
isOpen: boolean
|
|
27
|
+
/**
|
|
28
|
+
* The current node used to derive toggle button state.
|
|
29
|
+
*/
|
|
30
|
+
node: ProseMirrorNode
|
|
31
|
+
}
|
|
32
|
+
|
|
17
33
|
export interface DetailsOptions {
|
|
18
34
|
/**
|
|
19
35
|
* Specify if the open status should be saved in the document. Defaults to `false`.
|
|
@@ -29,6 +45,10 @@ export interface DetailsOptions {
|
|
|
29
45
|
HTMLAttributes: {
|
|
30
46
|
[key: string]: any
|
|
31
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Customizes the rendered toggle button.
|
|
50
|
+
*/
|
|
51
|
+
renderToggleButton: (options: DetailsRenderToggleButtonOptions) => void
|
|
32
52
|
}
|
|
33
53
|
|
|
34
54
|
declare module '@tiptap/core' {
|
|
@@ -65,6 +85,9 @@ export const Details = Node.create<DetailsOptions>({
|
|
|
65
85
|
persist: false,
|
|
66
86
|
openClassName: 'is-open',
|
|
67
87
|
HTMLAttributes: {},
|
|
88
|
+
renderToggleButton: ({ element, isOpen }) => {
|
|
89
|
+
element.setAttribute('aria-label', isOpen ? 'Collapse details content' : 'Expand details content')
|
|
90
|
+
},
|
|
68
91
|
}
|
|
69
92
|
},
|
|
70
93
|
|
|
@@ -118,13 +141,22 @@ export const Details = Node.create<DetailsOptions>({
|
|
|
118
141
|
|
|
119
142
|
toggle.type = 'button'
|
|
120
143
|
|
|
144
|
+
const renderToggleButton = (options: Omit<DetailsRenderToggleButtonOptions, 'element'>) => {
|
|
145
|
+
this.options.renderToggleButton({
|
|
146
|
+
element: toggle,
|
|
147
|
+
...options,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
121
151
|
dom.append(toggle)
|
|
122
152
|
|
|
123
153
|
const content = document.createElement('div')
|
|
124
154
|
|
|
125
155
|
dom.append(content)
|
|
126
156
|
|
|
127
|
-
const toggleDetailsContent = (setToValue?: boolean) => {
|
|
157
|
+
const toggleDetailsContent = (options?: { setToValue?: boolean; node?: ProseMirrorNode }) => {
|
|
158
|
+
const { setToValue, node: currentNode = node } = options || {}
|
|
159
|
+
|
|
128
160
|
if (setToValue !== undefined) {
|
|
129
161
|
if (setToValue) {
|
|
130
162
|
if (dom.classList.contains(this.options.openClassName)) {
|
|
@@ -141,12 +173,24 @@ export const Details = Node.create<DetailsOptions>({
|
|
|
141
173
|
dom.classList.toggle(this.options.openClassName)
|
|
142
174
|
}
|
|
143
175
|
|
|
176
|
+
const isOpen = dom.classList.contains(this.options.openClassName)
|
|
177
|
+
|
|
178
|
+
renderToggleButton({
|
|
179
|
+
isOpen,
|
|
180
|
+
node: currentNode,
|
|
181
|
+
})
|
|
182
|
+
|
|
144
183
|
const event = new Event('toggleDetailsContent')
|
|
145
184
|
const detailsContent = content.querySelector(':scope > div[data-type="detailsContent"]')
|
|
146
185
|
|
|
147
186
|
detailsContent?.dispatchEvent(event)
|
|
148
187
|
}
|
|
149
188
|
|
|
189
|
+
renderToggleButton({
|
|
190
|
+
isOpen: Boolean(node.attrs.open),
|
|
191
|
+
node,
|
|
192
|
+
})
|
|
193
|
+
|
|
150
194
|
if (node.attrs.open) {
|
|
151
195
|
setTimeout(() => toggleDetailsContent())
|
|
152
196
|
}
|
|
@@ -201,7 +245,11 @@ export const Details = Node.create<DetailsOptions>({
|
|
|
201
245
|
return false
|
|
202
246
|
}
|
|
203
247
|
|
|
204
|
-
|
|
248
|
+
const target = mutation.target
|
|
249
|
+
const isInsideWrapper = dom.contains(target)
|
|
250
|
+
const isInsideToggleButton = toggle.contains(target)
|
|
251
|
+
|
|
252
|
+
return isInsideToggleButton || !isInsideWrapper || dom === target
|
|
205
253
|
},
|
|
206
254
|
update: updatedNode => {
|
|
207
255
|
if (updatedNode.type !== this.type) {
|
|
@@ -210,7 +258,15 @@ export const Details = Node.create<DetailsOptions>({
|
|
|
210
258
|
|
|
211
259
|
// Only update the open state if set
|
|
212
260
|
if (updatedNode.attrs.open !== undefined) {
|
|
213
|
-
toggleDetailsContent(
|
|
261
|
+
toggleDetailsContent({
|
|
262
|
+
setToValue: updatedNode.attrs.open,
|
|
263
|
+
node: updatedNode,
|
|
264
|
+
})
|
|
265
|
+
} else {
|
|
266
|
+
renderToggleButton({
|
|
267
|
+
isOpen: dom.classList.contains(this.options.openClassName),
|
|
268
|
+
node: updatedNode,
|
|
269
|
+
})
|
|
214
270
|
}
|
|
215
271
|
|
|
216
272
|
return true
|