diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/Collapsible.css b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/Collapsible.css index f3e62e71c..e7b3742e4 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/Collapsible.css +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/Collapsible.css @@ -32,7 +32,7 @@ border-style: solid; border-color: transparent; border-width: 4px 6px 4px 6px; - border-left-color: #000; + border-left-color: var(--sn-stylekit-contrast-color); display: block; content: ''; position: absolute; diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContainerNode.ts b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContainerNode.ts index 5279dfc38..93b934c5f 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContainerNode.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContainerNode.ts @@ -8,8 +8,11 @@ import { DOMConversionMap, + DOMConversionOutput, + DOMExportOutput, EditorConfig, ElementNode, + LexicalEditor, LexicalNode, NodeKey, SerializedElementNode, @@ -25,6 +28,14 @@ type SerializedCollapsibleContainerNode = Spread< SerializedElementNode > +export function convertDetailsElement(domNode: HTMLDetailsElement): DOMConversionOutput | null { + const isOpen = domNode.open !== undefined ? domNode.open : true + const node = $createCollapsibleContainerNode(isOpen) + return { + node, + } +} + export class CollapsibleContainerNode extends ElementNode { __open: boolean @@ -41,10 +52,16 @@ export class CollapsibleContainerNode extends ElementNode { return new CollapsibleContainerNode(node.__open, node.__key) } - override createDOM(_: EditorConfig): HTMLElement { + override createDOM(_: EditorConfig, editor: LexicalEditor): HTMLElement { const dom = document.createElement('details') dom.classList.add('Collapsible__container') dom.open = this.__open + dom.addEventListener('toggle', () => { + const open = editor.getEditorState().read(() => this.getOpen()) + if (open !== dom.open) { + editor.update(() => this.toggleOpen()) + } + }) return dom } @@ -56,8 +73,15 @@ export class CollapsibleContainerNode extends ElementNode { return false } - static importDOM(): DOMConversionMap | null { - return {} + static importDOM(): DOMConversionMap | null { + return { + details: () => { + return { + conversion: convertDetailsElement, + priority: 1, + } + }, + } } static override importJSON(serializedNode: SerializedCollapsibleContainerNode): CollapsibleContainerNode { @@ -65,6 +89,14 @@ export class CollapsibleContainerNode extends ElementNode { return node } + exportDOM(): DOMExportOutput { + const element = document.createElement('details') + if (this.getLatest().__open) { + element.setAttribute('open', '') + } + return { element } + } + override exportJSON(): SerializedCollapsibleContainerNode { return { ...super.exportJSON(), @@ -80,7 +112,7 @@ export class CollapsibleContainerNode extends ElementNode { } getOpen(): boolean { - return this.__open + return this.getLatest().__open } toggleOpen(): void { diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContentNode.ts b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContentNode.ts index d2ec826d1..027bbc4a7 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContentNode.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleContentNode.ts @@ -6,7 +6,16 @@ * */ -import { DOMConversionMap, EditorConfig, ElementNode, LexicalNode, SerializedElementNode, Spread } from 'lexical' +import { + DOMConversionMap, + DOMConversionOutput, + DOMExportOutput, + EditorConfig, + ElementNode, + LexicalNode, + SerializedElementNode, + Spread, +} from 'lexical' type SerializedCollapsibleContentNode = Spread< { @@ -16,6 +25,13 @@ type SerializedCollapsibleContentNode = Spread< SerializedElementNode > +export function convertCollapsibleContentElement(): DOMConversionOutput | null { + const node = $createCollapsibleContentNode() + return { + node, + } +} + export class CollapsibleContentNode extends ElementNode { static override getType(): string { return 'collapsible-content' @@ -36,7 +52,17 @@ export class CollapsibleContentNode extends ElementNode { } static importDOM(): DOMConversionMap | null { - return {} + return { + div: (domNode: HTMLElement) => { + if (!domNode.hasAttribute('data-lexical-collapsible-content')) { + return null + } + return { + conversion: convertCollapsibleContentElement, + priority: 2, + } + }, + } } static override importJSON(_serializedNode: SerializedCollapsibleContentNode): CollapsibleContentNode { @@ -47,6 +73,12 @@ export class CollapsibleContentNode extends ElementNode { return true } + exportDOM(): DOMExportOutput { + const element = document.createElement('div') + element.setAttribute('data-lexical-collapsible-content', 'true') + return { element } + } + override exportJSON(): SerializedCollapsibleContentNode { return { ...super.exportJSON(), diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleTitleNode.ts b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleTitleNode.ts index 86487bd63..cbbf9bfec 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleTitleNode.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/CollapsiblePlugin/CollapsibleTitleNode.ts @@ -10,10 +10,10 @@ import { $createParagraphNode, $isElementNode, DOMConversionMap, - EditorConfig, + DOMConversionOutput, + DOMExportOutput, ElementFormatType, ElementNode, - LexicalEditor, LexicalNode, NodeKey, RangeSelection, @@ -32,6 +32,13 @@ type SerializedCollapsibleTitleNode = Spread< SerializedElementNode > +export function convertSummaryElement(): DOMConversionOutput | null { + const node = $createCollapsibleTitleNode() + return { + node, + } +} + export class CollapsibleTitleNode extends ElementNode { static override getType(): string { return 'collapsible-title' @@ -48,21 +55,11 @@ export class CollapsibleTitleNode extends ElementNode { return new CollapsibleTitleNode({ key: node.__key }) } - override createDOM(_config: EditorConfig, editor: LexicalEditor): HTMLElement { + override createDOM(): HTMLElement { const dom = document.createElement('summary') dom.classList.add('Collapsible__title') const format = this.getFormatType() dom.style.textAlign = format - dom.onclick = (event) => { - event.preventDefault() - event.stopPropagation() - editor.update(() => { - const containerNode = this.getParentOrThrow() - if ($isCollapsibleContainerNode(containerNode)) { - containerNode.toggleOpen() - } - }) - } return dom } @@ -71,13 +68,25 @@ export class CollapsibleTitleNode extends ElementNode { } static importDOM(): DOMConversionMap | null { - return {} + return { + summary: () => { + return { + conversion: convertSummaryElement, + priority: 1, + } + }, + } } static override importJSON(serializedNode: SerializedCollapsibleTitleNode): CollapsibleTitleNode { return $createCollapsibleTitleNode(serializedNode.format) } + exportDOM(): DOMExportOutput { + const element = document.createElement('summary') + return { element } + } + override exportJSON(): SerializedCollapsibleTitleNode { return { ...super.exportJSON(), @@ -91,7 +100,7 @@ export class CollapsibleTitleNode extends ElementNode { return true } - override insertNewAfter(): ElementNode { + override insertNewAfter(_: RangeSelection, restoreSelection = true): ElementNode { const containerNode = this.getParentOrThrow() if (!$isCollapsibleContainerNode(containerNode)) { @@ -114,7 +123,7 @@ export class CollapsibleTitleNode extends ElementNode { } } else { const paragraph = $createParagraphNode() - containerNode.insertAfter(paragraph) + containerNode.insertAfter(paragraph, restoreSelection) return paragraph } }