File
Blob: src/client/components/editor/extensions/details-block.tsx
| 1 | import { Extension } from "@tiptap/core"; |
| 2 | import Details, { DetailsContent, DetailsSummary } from "@tiptap/extension-details"; |
| 3 | import { Plugin } from "@tiptap/pm/state"; |
| 4 | import { DEFAULT_DETAILS_SUMMARY, DETAILS_SUMMARY_PLACEHOLDER } from "@/shared/editor/schema"; |
| 5 | import { applyMoveToDetailsContent } from "../controllers/details-block"; |
| 6 | |
| 7 | const DetailsBlock = Details.configure({ |
| 8 | persist: true, |
| 9 | HTMLAttributes: { class: "tiptap-details" }, |
| 10 | renderToggleButton: ({ element, isOpen, node }) => { |
| 11 | const summary = node.firstChild?.textContent?.trim() || DEFAULT_DETAILS_SUMMARY; |
| 12 | element.className = "tiptap-details-toggle"; |
| 13 | element.setAttribute("aria-label", `${isOpen ? "Collapse" : "Expand"} details: ${summary}`); |
| 14 | }, |
| 15 | }); |
| 16 | |
| 17 | const DetailsBlockSummary = DetailsSummary.configure({ |
| 18 | HTMLAttributes: { |
| 19 | class: "tiptap-details-summary", |
| 20 | "data-placeholder": DETAILS_SUMMARY_PLACEHOLDER, |
| 21 | }, |
| 22 | }); |
| 23 | |
| 24 | const DetailsBlockContent = DetailsContent.configure({ |
| 25 | HTMLAttributes: { class: "tiptap-details-content" }, |
| 26 | }); |
| 27 | |
| 28 | const DetailsBlockKeyboardNavigation = Extension.create({ |
| 29 | name: "detailsBlockKeyboardNavigation", |
| 30 | |
| 31 | addProseMirrorPlugins() { |
| 32 | return [ |
| 33 | new Plugin({ |
| 34 | props: { |
| 35 | handleDOMEvents: { |
| 36 | keydown: (view, event) => { |
| 37 | if (event.key !== "Tab" || event.shiftKey) return false; |
| 38 | |
| 39 | const tr = view.state.tr; |
| 40 | if (!applyMoveToDetailsContent(tr)) return false; |
| 41 | |
| 42 | event.preventDefault(); |
| 43 | view.dispatch(tr.scrollIntoView()); |
| 44 | view.focus(); |
| 45 | return true; |
| 46 | }, |
| 47 | }, |
| 48 | }, |
| 49 | }), |
| 50 | ]; |
| 51 | }, |
| 52 | }); |
| 53 | |
| 54 | export const DetailsBlockExtensions = [ |
| 55 | DetailsBlock, |
| 56 | DetailsBlockSummary, |
| 57 | DetailsBlockContent, |
| 58 | DetailsBlockKeyboardNavigation, |
| 59 | ] as const; |