mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 18:49:00 +01:00
feat(react): render raw react components
This commit is contained in:
parent
8abd3ed3f1
commit
afe3904ea3
@ -8,7 +8,6 @@ import electronContextMenu from "./menus/electron_context_menu.js";
|
||||
import glob from "./services/glob.js";
|
||||
import { t } from "./services/i18n.js";
|
||||
import options from "./services/options.js";
|
||||
import server from "./services/server.js";
|
||||
import type ElectronRemote from "@electron/remote";
|
||||
import type Electron from "electron";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
|
||||
@ -25,12 +25,12 @@ import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js";
|
||||
import PopupEditorDialog from "../widgets/dialogs/popup_editor.js";
|
||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||
import NoteIconWidget from "../widgets/note_icon.js";
|
||||
import NoteTitleWidget from "../widgets/note_title.js";
|
||||
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
|
||||
import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import NoteListWidget from "../widgets/note_list.js";
|
||||
import { CallToActionDialog } from "../widgets/dialogs/call_to_action.jsx";
|
||||
import NoteTitleWidget from "../widgets/note_title.jsx";
|
||||
|
||||
export function applyModals(rootContainer: RootContainer) {
|
||||
rootContainer
|
||||
@ -62,7 +62,7 @@ export function applyModals(rootContainer: RootContainer) {
|
||||
.css("align-items", "center")
|
||||
.cssBlock(".title-row > * { margin: 5px; }")
|
||||
.child(new NoteIconWidget())
|
||||
.child(new NoteTitleWidget()))
|
||||
.child(<NoteTitleWidget />))
|
||||
.child(new ClassicEditorToolbar())
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(new NoteDetailWidget())
|
||||
@ -1,7 +1,9 @@
|
||||
import { isValidElement, VNode } from "preact";
|
||||
import Component, { TypedComponent } from "../components/component.js";
|
||||
import froca from "../services/froca.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import toastService from "../services/toast.js";
|
||||
import { renderReactWidget } from "./react/react_utils.jsx";
|
||||
|
||||
export class TypedBasicWidget<T extends TypedComponent<any>> extends TypedComponent<T> {
|
||||
protected attrs: Record<string, string>;
|
||||
@ -22,11 +24,14 @@ export class TypedBasicWidget<T extends TypedComponent<any>> extends TypedCompon
|
||||
this.childPositionCounter = 10;
|
||||
}
|
||||
|
||||
child(...components: T[]) {
|
||||
if (!components) {
|
||||
child(..._components: (T | VNode)[]) {
|
||||
if (!_components) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Convert any React components to legacy wrapped components.
|
||||
const components = wrapReactWidgets(_components);
|
||||
|
||||
super.child(...components);
|
||||
|
||||
for (const component of components) {
|
||||
@ -258,3 +263,30 @@ export class TypedBasicWidget<T extends TypedComponent<any>> extends TypedCompon
|
||||
* For information on using widgets, see the tutorial {@tutorial widget_basics}.
|
||||
*/
|
||||
export default class BasicWidget extends TypedBasicWidget<Component> {}
|
||||
|
||||
export function wrapReactWidgets<T extends TypedComponent<any>>(components: (T | VNode)[]) {
|
||||
const wrappedResult: T[] = [];
|
||||
for (const component of components) {
|
||||
if (isValidElement(component)) {
|
||||
wrappedResult.push(new ReactWrappedWidget(component) as unknown as T);
|
||||
} else {
|
||||
wrappedResult.push(component);
|
||||
}
|
||||
}
|
||||
return wrappedResult;
|
||||
}
|
||||
|
||||
class ReactWrappedWidget extends BasicWidget {
|
||||
|
||||
private el: VNode;
|
||||
|
||||
constructor(el: VNode) {
|
||||
super();
|
||||
this.el = el;
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = renderReactWidget(this, this.el);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
7
apps/client/src/widgets/note_title.tsx
Normal file
7
apps/client/src/widgets/note_title.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export default function NoteTitleWidget() {
|
||||
return (
|
||||
<>
|
||||
<p>Hi</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -3,7 +3,7 @@ import { t } from "../../services/i18n";
|
||||
import { ComponentChildren } from "preact";
|
||||
import type { CSSProperties, RefObject } from "preact/compat";
|
||||
import { openDialog } from "../../services/dialog";
|
||||
import { ParentComponent } from "./ReactBasicWidget";
|
||||
import { ParentComponent } from "./react_utils";
|
||||
import { Modal as BootstrapModal } from "bootstrap";
|
||||
import { memo } from "preact/compat";
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
import { createContext, JSX, render } from "preact";
|
||||
import { JSX } from "preact";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import Component from "../../components/component.js";
|
||||
|
||||
export const ParentComponent = createContext<Component | null>(null);
|
||||
|
||||
import { renderReactWidget } from "./react_utils.jsx";
|
||||
export default abstract class ReactBasicWidget extends BasicWidget {
|
||||
|
||||
abstract get component(): JSX.Element;
|
||||
@ -13,27 +10,3 @@ export default abstract class ReactBasicWidget extends BasicWidget {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a React component and returns the corresponding DOM element wrapped in JQuery.
|
||||
*
|
||||
* @param parentComponent the parent Trilium component for the component to be able to handle events.
|
||||
* @param el the JSX element to render.
|
||||
* @returns the rendered wrapped DOM element.
|
||||
*/
|
||||
export function renderReactWidget(parentComponent: Component, el: JSX.Element) {
|
||||
return renderReactWidgetAtElement(parentComponent, el, new DocumentFragment()).children();
|
||||
}
|
||||
|
||||
export function renderReactWidgetAtElement(parentComponent: Component, el: JSX.Element, container: Element | DocumentFragment) {
|
||||
render((
|
||||
<ParentComponent.Provider value={parentComponent}>
|
||||
{el}
|
||||
</ParentComponent.Provider>
|
||||
), container);
|
||||
return $(container) as JQuery<HTMLElement>;
|
||||
}
|
||||
|
||||
export function disposeReactWidget(container: Element) {
|
||||
render(null, container);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { EventData, EventNames } from "../../components/app_context";
|
||||
import { ParentComponent } from "./ReactBasicWidget";
|
||||
import { ParentComponent } from "./react_utils";
|
||||
import SpacedUpdate from "../../services/spaced_update";
|
||||
import { OptionNames } from "@triliumnext/commons";
|
||||
import options, { type OptionValue } from "../../services/options";
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
import type { RefObject } from "preact";
|
||||
|
||||
/**
|
||||
* Takes in a React ref and returns a corresponding JQuery selector.
|
||||
*
|
||||
* @param ref the React ref from which to obtain the jQuery selector.
|
||||
* @returns the corresponding jQuery selector.
|
||||
*/
|
||||
export function refToJQuerySelector<T extends HTMLElement>(ref: RefObject<T> | null): JQuery<T> {
|
||||
if (ref?.current) {
|
||||
return $(ref.current);
|
||||
} else {
|
||||
return $();
|
||||
}
|
||||
}
|
||||
42
apps/client/src/widgets/react/react_utils.tsx
Normal file
42
apps/client/src/widgets/react/react_utils.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { createContext, render, type JSX, type RefObject } from "preact";
|
||||
import Component from "../../components/component";
|
||||
|
||||
export const ParentComponent = createContext<Component | null>(null);
|
||||
|
||||
/**
|
||||
* Takes in a React ref and returns a corresponding JQuery selector.
|
||||
*
|
||||
* @param ref the React ref from which to obtain the jQuery selector.
|
||||
* @returns the corresponding jQuery selector.
|
||||
*/
|
||||
export function refToJQuerySelector<T extends HTMLElement>(ref: RefObject<T> | null): JQuery<T> {
|
||||
if (ref?.current) {
|
||||
return $(ref.current);
|
||||
} else {
|
||||
return $();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a React component and returns the corresponding DOM element wrapped in JQuery.
|
||||
*
|
||||
* @param parentComponent the parent Trilium component for the component to be able to handle events.
|
||||
* @param el the JSX element to render.
|
||||
* @returns the rendered wrapped DOM element.
|
||||
*/
|
||||
export function renderReactWidget(parentComponent: Component, el: JSX.Element) {
|
||||
return renderReactWidgetAtElement(parentComponent, el, new DocumentFragment()).children();
|
||||
}
|
||||
|
||||
export function renderReactWidgetAtElement(parentComponent: Component, el: JSX.Element, container: Element | DocumentFragment) {
|
||||
render((
|
||||
<ParentComponent.Provider value={parentComponent}>
|
||||
{el}
|
||||
</ParentComponent.Provider>
|
||||
), container);
|
||||
return $(container) as JQuery<HTMLElement>;
|
||||
}
|
||||
|
||||
export function disposeReactWidget(container: Element) {
|
||||
render(null, container);
|
||||
}
|
||||
@ -19,7 +19,7 @@ import bulkActionService from "../../services/bulk_action.js";
|
||||
import { Dropdown } from "bootstrap";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { AttributeType } from "../../entities/fattribute.js";
|
||||
import { renderReactWidget } from "../react/ReactBasicWidget.jsx";
|
||||
import { renderReactWidget } from "../react/react_utils.jsx";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="search-definition-widget">
|
||||
|
||||
@ -6,7 +6,7 @@ import type { LibraryItem } from "@excalidraw/excalidraw/types";
|
||||
import type { Theme } from "@excalidraw/excalidraw/element/types";
|
||||
import type Canvas from "./canvas_el.js";
|
||||
import { CanvasContent } from "./canvas_el.js";
|
||||
import { renderReactWidget } from "../react/ReactBasicWidget.jsx";
|
||||
import { renderReactWidget } from "../react/react_utils.jsx";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="canvas-widget note-detail-canvas note-detail-printable note-detail">
|
||||
|
||||
@ -5,7 +5,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 { disposeReactWidget, renderReactWidget, renderReactWidgetAtElement } from "../react/ReactBasicWidget.jsx";
|
||||
import { disposeReactWidget, renderReactWidgetAtElement } from "../react/react_utils.jsx";
|
||||
import ImageSettings from "./options/images.jsx";
|
||||
import AdvancedSettings from "./options/advanced.jsx";
|
||||
import InternationalizationOptions from "./options/i18n.jsx";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user