feat(client/bundle): support rendering in other places

This commit is contained in:
Elian Doran 2025-12-20 23:16:19 +02:00
parent c558255450
commit 76f054bbd5
No known key found for this signature in database
3 changed files with 27 additions and 6 deletions

View File

@ -1,3 +1,6 @@
import { h, VNode } from "preact";
import Component from "../components/component.js";
import BasicWidget from "../widgets/basic_widget.js"; import BasicWidget from "../widgets/basic_widget.js";
import RightPanelWidget from "../widgets/right_panel_widget.js"; import RightPanelWidget from "../widgets/right_panel_widget.js";
import froca from "./froca.js"; import froca from "./froca.js";
@ -77,24 +80,42 @@ export class WidgetsByParent {
} }
add(widget: Widget) { add(widget: Widget) {
let hasParentWidget = false;
let isPreact = false;
if ("type" in widget && widget.type === "preact-widget") { if ("type" in widget && widget.type === "preact-widget") {
// React-based script. // React-based script.
const reactWidget = widget as WidgetDefinitionWithType; const reactWidget = widget as WidgetDefinitionWithType;
this.preactWidgets[reactWidget.parent] = this.preactWidgets[reactWidget.parent] || []; this.preactWidgets[reactWidget.parent] = this.preactWidgets[reactWidget.parent] || [];
this.preactWidgets[reactWidget.parent].push(reactWidget); this.preactWidgets[reactWidget.parent].push(reactWidget);
isPreact = true;
hasParentWidget = !!reactWidget.parent;
} else if ("parentWidget" in widget && widget.parentWidget) { } else if ("parentWidget" in widget && widget.parentWidget) {
this.legacyWidgets[widget.parentWidget] = this.legacyWidgets[widget.parentWidget] || []; this.legacyWidgets[widget.parentWidget] = this.legacyWidgets[widget.parentWidget] || [];
this.legacyWidgets[widget.parentWidget].push(widget); this.legacyWidgets[widget.parentWidget].push(widget);
} else { hasParentWidget = !!widget.parentWidget;
showErrorForScriptNote(widget._noteId, t("toast.widget-missing-parent")); }
if (!hasParentWidget) {
showErrorForScriptNote(widget._noteId, t("toast.widget-missing-parent", {
property: isPreact ? "parent" : "parentWidget"
}));
} }
} }
get(parentName: ParentName) { get(parentName: ParentName) {
if (!this.legacyWidgets[parentName]) { const widgets: (Component | VNode)[] = this.getLegacyWidgets(parentName);
return []; for (const preactWidget of this.getPreactWidgets(parentName)) {
const el = h(preactWidget.render, {});
// TODO: set position here.
widgets.push(el);
} }
return widgets;
}
getLegacyWidgets(parentName: ParentName): (BasicWidget | RightPanelWidget)[] {
if (!this.legacyWidgets[parentName]) return [];
return ( return (
this.legacyWidgets[parentName] this.legacyWidgets[parentName]
// previously, custom widgets were provided as a single instance, but that has the disadvantage // previously, custom widgets were provided as a single instance, but that has the disadvantage

View File

@ -29,7 +29,7 @@
"widget-render-error": { "widget-render-error": {
"title": "Failed to render a custom React widget" "title": "Failed to render a custom React widget"
}, },
"widget-missing-parent": "Custom widget does not have mandatory 'parentWidget' property defined.", "widget-missing-parent": "Custom widget does not have mandatory '{{property}}' property defined.",
"open-script-note": "Open script note" "open-script-note": "Open script note"
}, },
"add_link": { "add_link": {

View File

@ -69,7 +69,7 @@ function useItems(rightPaneVisible: boolean, widgetsByParent: WidgetsByParent) {
enabled: noteType === "text" && highlightsList.length > 0, enabled: noteType === "text" && highlightsList.length > 0,
position: 20, position: 20,
}, },
...widgetsByParent.get("right-pane").map((widget, i) => ({ ...widgetsByParent.getLegacyWidgets("right-pane").map((widget, i) => ({
el: <CustomLegacyWidget key={widget._noteId} originalWidget={widget as LegacyRightPanelWidget} />, el: <CustomLegacyWidget key={widget._noteId} originalWidget={widget as LegacyRightPanelWidget} />,
enabled: true, enabled: true,
position: widget.position ?? 30 + i * 10 position: widget.position ?? 30 + i * 10