diff --git a/apps/client/src/widgets/containers/split_note_container.ts b/apps/client/src/widgets/containers/split_note_container.ts index 99165437c..12d417973 100644 --- a/apps/client/src/widgets/containers/split_note_container.ts +++ b/apps/client/src/widgets/containers/split_note_container.ts @@ -2,6 +2,7 @@ import FlexContainer from "./flex_container.js"; import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js"; import type BasicWidget from "../basic_widget.js"; import type NoteContext from "../../components/note_context.js"; +import Component from "../../components/component.js"; interface NoteContextEvent { noteContext: NoteContext; @@ -152,6 +153,8 @@ export default class SplitNoteContainer extends FlexContainer { for (const ntxId of ntxIds) { this.$widget.find(`[data-ntx-id="${ntxId}"]`).remove(); + const widget = this.widgets[ntxId]; + recursiveCleanup(widget); delete this.widgets[ntxId]; } } @@ -237,3 +240,12 @@ export default class SplitNoteContainer extends FlexContainer { return Promise.all(promises); } } + +function recursiveCleanup(widget: Component) { + for (const child of widget.children) { + recursiveCleanup(child); + } + if ("cleanup" in widget && typeof widget.cleanup === "function") { + widget.cleanup(); + } +} diff --git a/apps/client/src/widgets/react/ReactBasicWidget.tsx b/apps/client/src/widgets/react/ReactBasicWidget.tsx index 311293000..b813be3bd 100644 --- a/apps/client/src/widgets/react/ReactBasicWidget.tsx +++ b/apps/client/src/widgets/react/ReactBasicWidget.tsx @@ -22,11 +22,18 @@ export default abstract class ReactBasicWidget extends BasicWidget { * @returns the rendered wrapped DOM element. */ export function renderReactWidget(parentComponent: Component, el: JSX.Element) { - const renderContainer = new DocumentFragment(); + return renderReactWidgetAtElement(parentComponent, el, new DocumentFragment()).children(); +} + +export function renderReactWidgetAtElement(parentComponent: Component, el: JSX.Element, container: Element | DocumentFragment) { render(( {el} - ), renderContainer); - return $(renderContainer.children) as JQuery; + ), container); + return $(container) as JQuery; } + +export function disposeReactWidget(container: Element) { + render(null, container); +} \ No newline at end of file diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 5c18ad4b2..482aef647 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -68,9 +68,17 @@ export default function useTriliumEvent(eventName: T, hand return; } - // Remove the event handler from the array. - const newEventHandlers = eventHandlers.filter(e => e !== handler); - registeredHandlers.get(parentWidget)?.set(eventName, newEventHandlers); + // Remove the event handler from the array. + const newEventHandlers = eventHandlers.filter(e => e !== handler); + if (newEventHandlers.length) { + registeredHandlers.get(parentWidget)?.set(eventName, newEventHandlers); + } else { + registeredHandlers.get(parentWidget)?.delete(eventName); + } + + if (!registeredHandlers.get(parentWidget)?.size) { + registeredHandlers.delete(parentWidget); + } }; }, [ eventName, parentWidget, handler ]); } diff --git a/apps/client/src/widgets/type_widgets/content_widget.tsx b/apps/client/src/widgets/type_widgets/content_widget.tsx index 8757df2b4..44c67a9eb 100644 --- a/apps/client/src/widgets/type_widgets/content_widget.tsx +++ b/apps/client/src/widgets/type_widgets/content_widget.tsx @@ -7,7 +7,7 @@ import { t } from "../../services/i18n.js"; import type BasicWidget from "../basic_widget.js"; import type { JSX } from "preact/jsx-runtime"; import AppearanceSettings from "./options/appearance.jsx"; -import { renderReactWidget } from "../react/ReactBasicWidget.jsx"; +import { disposeReactWidget, renderReactWidget, renderReactWidgetAtElement } from "../react/ReactBasicWidget.jsx"; import ImageSettings from "./options/images.jsx"; import AdvancedSettings from "./options/advanced.jsx"; import InternationalizationOptions from "./options/i18n.jsx"; @@ -21,6 +21,7 @@ import TextNoteSettings from "./options/text_notes.jsx"; import CodeNoteSettings from "./options/code_notes.jsx"; import OtherSettings from "./options/other.jsx"; import BackendLogWidget from "./content/backend_log.js"; +import { unmountComponentAtNode } from "preact/compat"; const TPL = /*html*/`