feat: Persist collapsible block state in Super notes (#2119)

This commit is contained in:
Aman Harwara
2022-12-24 20:35:41 +05:30
committed by GitHub
parent b8da877804
commit 577318e208
4 changed files with 48 additions and 26 deletions

View File

@@ -20,6 +20,7 @@ type SerializedCollapsibleContainerNode = Spread<
{ {
type: 'collapsible-container'; type: 'collapsible-container';
version: 1; version: 1;
open: boolean;
}, },
SerializedElementNode SerializedElementNode
>; >;
@@ -29,25 +30,27 @@ export class CollapsibleContainerNode extends ElementNode {
constructor(open: boolean, key?: NodeKey) { constructor(open: boolean, key?: NodeKey) {
super(key); super(key);
this.__open = open; this.__open = open ?? false;
} }
static getType(): string { static override getType(): string {
return 'collapsible-container'; return 'collapsible-container';
} }
static clone(node: CollapsibleContainerNode): CollapsibleContainerNode { static override clone(
node: CollapsibleContainerNode,
): CollapsibleContainerNode {
return new CollapsibleContainerNode(node.__open, node.__key); return new CollapsibleContainerNode(node.__open, node.__key);
} }
createDOM(config: EditorConfig): HTMLElement { override createDOM(config: EditorConfig): HTMLElement {
const dom = document.createElement('details'); const dom = document.createElement('details');
dom.classList.add('Collapsible__container'); dom.classList.add('Collapsible__container');
dom.open = this.__open; dom.open = this.__open;
return dom; return dom;
} }
updateDOM( override updateDOM(
prevNode: CollapsibleContainerNode, prevNode: CollapsibleContainerNode,
dom: HTMLDetailsElement, dom: HTMLDetailsElement,
): boolean { ): boolean {
@@ -62,18 +65,19 @@ export class CollapsibleContainerNode extends ElementNode {
return {}; return {};
} }
static importJSON( static override importJSON(
serializedNode: SerializedCollapsibleContainerNode, serializedNode: SerializedCollapsibleContainerNode,
): CollapsibleContainerNode { ): CollapsibleContainerNode {
const node = $createCollapsibleContainerNode(); const node = $createCollapsibleContainerNode(serializedNode.open);
return node; return node;
} }
exportJSON(): SerializedCollapsibleContainerNode { override exportJSON(): SerializedCollapsibleContainerNode {
return { return {
...super.exportJSON(), ...super.exportJSON(),
type: 'collapsible-container', type: 'collapsible-container',
version: 1, version: 1,
open: this.__open,
}; };
} }
@@ -91,8 +95,10 @@ export class CollapsibleContainerNode extends ElementNode {
} }
} }
export function $createCollapsibleContainerNode(): CollapsibleContainerNode { export function $createCollapsibleContainerNode(
return new CollapsibleContainerNode(true); open: boolean,
): CollapsibleContainerNode {
return new CollapsibleContainerNode(open);
} }
export function $isCollapsibleContainerNode( export function $isCollapsibleContainerNode(

View File

@@ -24,21 +24,24 @@ type SerializedCollapsibleContentNode = Spread<
>; >;
export class CollapsibleContentNode extends ElementNode { export class CollapsibleContentNode extends ElementNode {
static getType(): string { static override getType(): string {
return 'collapsible-content'; return 'collapsible-content';
} }
static clone(node: CollapsibleContentNode): CollapsibleContentNode { static override clone(node: CollapsibleContentNode): CollapsibleContentNode {
return new CollapsibleContentNode(node.__key); return new CollapsibleContentNode(node.__key);
} }
createDOM(config: EditorConfig): HTMLElement { override createDOM(config: EditorConfig): HTMLElement {
const dom = document.createElement('div'); const dom = document.createElement('div');
dom.classList.add('Collapsible__content'); dom.classList.add('Collapsible__content');
return dom; return dom;
} }
updateDOM(prevNode: CollapsibleContentNode, dom: HTMLElement): boolean { override updateDOM(
prevNode: CollapsibleContentNode,
dom: HTMLElement,
): boolean {
return false; return false;
} }
@@ -46,17 +49,17 @@ export class CollapsibleContentNode extends ElementNode {
return {}; return {};
} }
static importJSON( static override importJSON(
serializedNode: SerializedCollapsibleContentNode, serializedNode: SerializedCollapsibleContentNode,
): CollapsibleContentNode { ): CollapsibleContentNode {
return $createCollapsibleContentNode(); return $createCollapsibleContentNode();
} }
isShadowRoot(): boolean { override isShadowRoot(): boolean {
return true; return true;
} }
exportJSON(): SerializedCollapsibleContentNode { override exportJSON(): SerializedCollapsibleContentNode {
return { return {
...super.exportJSON(), ...super.exportJSON(),
type: 'collapsible-content', type: 'collapsible-content',

View File

@@ -31,21 +31,34 @@ type SerializedCollapsibleTitleNode = Spread<
>; >;
export class CollapsibleTitleNode extends ElementNode { export class CollapsibleTitleNode extends ElementNode {
static getType(): string { static override getType(): string {
return 'collapsible-title'; return 'collapsible-title';
} }
static clone(node: CollapsibleTitleNode): CollapsibleTitleNode { static override clone(node: CollapsibleTitleNode): CollapsibleTitleNode {
return new CollapsibleTitleNode(node.__key); return new CollapsibleTitleNode(node.__key);
} }
createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement { override createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement {
const dom = document.createElement('summary'); const dom = document.createElement('summary');
dom.classList.add('Collapsible__title'); dom.classList.add('Collapsible__title');
dom.onclick = (event) => {
event.preventDefault();
event.stopPropagation();
editor.update(() => {
const containerNode = this.getParentOrThrow();
if ($isCollapsibleContainerNode(containerNode)) {
containerNode.toggleOpen();
}
});
};
return dom; return dom;
} }
updateDOM(prevNode: CollapsibleTitleNode, dom: HTMLElement): boolean { override updateDOM(
prevNode: CollapsibleTitleNode,
dom: HTMLElement,
): boolean {
return false; return false;
} }
@@ -53,13 +66,13 @@ export class CollapsibleTitleNode extends ElementNode {
return {}; return {};
} }
static importJSON( static override importJSON(
serializedNode: SerializedCollapsibleTitleNode, serializedNode: SerializedCollapsibleTitleNode,
): CollapsibleTitleNode { ): CollapsibleTitleNode {
return $createCollapsibleTitleNode(); return $createCollapsibleTitleNode();
} }
exportJSON(): SerializedCollapsibleTitleNode { override exportJSON(): SerializedCollapsibleTitleNode {
return { return {
...super.exportJSON(), ...super.exportJSON(),
type: 'collapsible-title', type: 'collapsible-title',
@@ -67,12 +80,12 @@ export class CollapsibleTitleNode extends ElementNode {
}; };
} }
collapseAtStart(_selection: RangeSelection): boolean { override collapseAtStart(_selection: RangeSelection): boolean {
this.getParentOrThrow().insertBefore(this); this.getParentOrThrow().insertBefore(this);
return true; return true;
} }
insertNewAfter(): ElementNode { override insertNewAfter(): ElementNode {
const containerNode = this.getParentOrThrow(); const containerNode = this.getParentOrThrow();
if (!$isCollapsibleContainerNode(containerNode)) { if (!$isCollapsibleContainerNode(containerNode)) {

View File

@@ -204,7 +204,7 @@ export default function CollapsiblePlugin(): JSX.Element | null {
const content = $createCollapsibleContentNode().append( const content = $createCollapsibleContentNode().append(
$createParagraphNode(), $createParagraphNode(),
); );
const container = $createCollapsibleContainerNode().append( const container = $createCollapsibleContainerNode(true).append(
title, title,
content, content,
); );