diff --git a/.changeset/stale-jars-punch.md b/.changeset/stale-jars-punch.md new file mode 100644 index 00000000..75719d14 --- /dev/null +++ b/.changeset/stale-jars-punch.md @@ -0,0 +1,5 @@ +--- +"@stackoverflow/stacks-editor": minor +--- + +Snippets - Adding in callback hooks for Fullscreen/Return diff --git a/plugins/official/stack-snippets/src/common.ts b/plugins/official/stack-snippets/src/common.ts index 9568422a..f14c737f 100644 --- a/plugins/official/stack-snippets/src/common.ts +++ b/plugins/official/stack-snippets/src/common.ts @@ -21,6 +21,12 @@ export interface StackSnippetOptions { css?: string, html?: string ) => void; + + /** Function to handle any required marshalling of components to render fullscreen correctly */ + onFullscreenExpand?: () => void; + + /** Function to handle any required marshalling of components to return from fullscreen correctly */ + onFullscreenReturn?: () => void; } export interface SnippetMetadata { diff --git a/plugins/official/stack-snippets/src/snippet-view.ts b/plugins/official/stack-snippets/src/snippet-view.ts index 68036e42..b6f10136 100644 --- a/plugins/official/stack-snippets/src/snippet-view.ts +++ b/plugins/official/stack-snippets/src/snippet-view.ts @@ -19,6 +19,7 @@ export class StackSnippetView implements NodeView { this.view = view; this.getPos = getPos; this.node = node; + this.isFullscreen = false; //Never start fullscreened this.snippetMetadata = getSnippetMetadata(node); const codeIsShown: boolean = @@ -112,7 +113,6 @@ export class StackSnippetView implements NodeView { snippetResultButtonContainer ); this.fullscreenReturnButton.classList.add("d-none"); - this.snippetResultButtonContainer = snippetResultButtonContainer; } snippetResult.appendChild(ctas); @@ -187,6 +187,7 @@ export class StackSnippetView implements NodeView { //Fullscreen the results, if the node meta needs it if (node.attrs.fullscreen) { + //Verify the styles are correct - this is idempotent if (!this.dom.classList.contains("snippet-fullscreen")) { //We use `.snippet-fullscreen` as a marker for the rest of the styling this.dom.classList.add("snippet-fullscreen"); @@ -199,7 +200,15 @@ export class StackSnippetView implements NodeView { if (this.fullscreenReturnButton?.classList.contains("d-none")) { this.fullscreenReturnButton.classList.remove("d-none"); } + //If we weren't in fullscreen, trigger the fullscreen callback + if (this.isFullscreen == false) { + if (this.opts.onFullscreenExpand) { + this.opts.onFullscreenExpand(); + } + this.isFullscreen = true; + } } else { + //Verify the styles are correct - this is idempotent if (this.dom.classList.contains("snippet-fullscreen")) { //We use `.snippet-fullscreen` as a marker for the rest of the styling this.dom.classList.remove("snippet-fullscreen"); @@ -211,6 +220,14 @@ export class StackSnippetView implements NodeView { if (!this.fullscreenReturnButton?.classList.contains("d-none")) { this.fullscreenReturnButton?.classList.add("d-none"); } + + //If we were in fullscreen, trigger the return + if (this.isFullscreen == true) { + if (this.opts.onFullscreenReturn) { + this.opts.onFullscreenReturn(); + } + this.isFullscreen = false; + } } //Re-run execution the snippet if something has changed, or we don't yet have a result @@ -239,12 +256,12 @@ export class StackSnippetView implements NodeView { private readonly getPos: () => number; private snippetMetadata: SnippetMetadata; private contentNode: Node; - private snippetResultButtonContainer: HTMLDivElement; private showButton: HTMLButtonElement; private hideButton: HTMLButtonElement; private fullscreenButton: HTMLButtonElement; private fullscreenReturnButton: HTMLButtonElement; private node: ProseMirrorNode; + private isFullscreen: boolean; resultContainer: HTMLDivElement; dom: HTMLElement; contentDOM: HTMLElement; diff --git a/plugins/official/stack-snippets/test/snippet-view.test.ts b/plugins/official/stack-snippets/test/snippet-view.test.ts index ea183f17..fbdb3aba 100644 --- a/plugins/official/stack-snippets/test/snippet-view.test.ts +++ b/plugins/official/stack-snippets/test/snippet-view.test.ts @@ -204,4 +204,54 @@ describe("StackSnippetView", () => { expect(toggleLink.textContent).toBe("Hide code snippet"); }); }); + + describe("Fullscren/Return Snippet", () => { + it("should trigger onFullscreenExpand callback if defined", () => { + let fullscreenExpandCalled = false; + const view = buildView({ + renderer: () => { + return Promise.resolve(null); + }, + openSnippetsModal: () => {}, + onFullscreenExpand: () => { + fullscreenExpandCalled = true; + }, + }); + + const [fullscreenButton] = view.dom.querySelectorAll( + ".snippet-result-buttons > button.s-btn[aria-label='Expand Snippet']" + ); + + //Fullscreen + (fullscreenButton).click(); + + expect(fullscreenExpandCalled).toBe(true); + }); + + it("should trigger onFullscreenReturn callback if defined", () => { + let fullscreenReturnCalled = false; + const view = buildView({ + renderer: () => { + return Promise.resolve(null); + }, + openSnippetsModal: () => {}, + onFullscreenReturn: () => { + fullscreenReturnCalled = true; + }, + }); + const [fullscreenButton] = view.dom.querySelectorAll( + ".snippet-result-buttons > button.s-btn[aria-label='Expand Snippet']" + ); + const [fullscreenReturn] = view.dom.querySelectorAll( + ".snippet-result-buttons > button.s-btn[aria-label='Return to post']" + ); + + //Fullscreen + (fullscreenButton).click(); + //And then return + (fullscreenReturn).click(); + + expect(fullscreenReturnCalled).toBe(true); + }); + }); });