mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-28 16:06:47 +01:00
refactor: improve portal provider logic
This commit is contained in:
2
packages/editor/dist/components/button.d.ts
vendored
2
packages/editor/dist/components/button.d.ts
vendored
File diff suppressed because one or more lines are too long
53
packages/editor/dist/components/button.js
vendored
53
packages/editor/dist/components/button.js
vendored
@@ -10,12 +10,11 @@ var __assign = (this && this.__assign) || function () {
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { useCallback, useRef } from "react";
|
||||
import { forwardRef, useCallback, useRef } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { Button as RebassButton } from "rebass";
|
||||
export function Button(props) {
|
||||
export var Button = forwardRef(function (props, forwardedRef) {
|
||||
var buttonRef = useRef();
|
||||
var touchStartTime = useRef(0);
|
||||
useEffect(function () {
|
||||
if (!buttonRef.current)
|
||||
return;
|
||||
@@ -23,59 +22,21 @@ export function Button(props) {
|
||||
passive: false,
|
||||
capture: true,
|
||||
});
|
||||
// buttonRef.current.addEventListener("touchmove", onTouchMove, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
// buttonRef.current.addEventListener("touchend", onTouchEnd, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
// buttonRef.current.addEventListener("touchstart", onTouchStart, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
return function () {
|
||||
var _a;
|
||||
(_a = buttonRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener("mousedown", onMouseDown, {
|
||||
capture: true,
|
||||
});
|
||||
// buttonRef.current?.removeEventListener("touchmove", onTouchMove, {
|
||||
// capture: true,
|
||||
// });
|
||||
// buttonRef.current?.removeEventListener("touchend", onTouchEnd, {
|
||||
// capture: true,
|
||||
// });
|
||||
// buttonRef.current?.removeEventListener("touchstart", onTouchStart, {
|
||||
// capture: true,
|
||||
// });
|
||||
};
|
||||
}, []);
|
||||
var onMouseDown = useCallback(function (e) {
|
||||
e.preventDefault();
|
||||
}, []);
|
||||
// const onTouchEnd = useCallback((e) => {
|
||||
// e.preventDefault();
|
||||
// const now = Date.now();
|
||||
// setTimeout(() => {
|
||||
// console.log(now, touchStartTime.current);
|
||||
// if (touchStartTime.current === 0) return;
|
||||
// if (now - touchStartTime.current > 300) return;
|
||||
// //@ts-ignore
|
||||
// props.onClick(e);
|
||||
// }, 1);
|
||||
// }, []);
|
||||
// const onTouchStart = useCallback((e) => {
|
||||
// touchStartTime.current = Date.now();
|
||||
// console.log("HELLO!");
|
||||
// e.preventDefault();
|
||||
// }, []);
|
||||
// const onTouchMove = useCallback((e) => {
|
||||
// console.log("HELLO!");
|
||||
// touchStartTime.current = 0;
|
||||
// }, []);
|
||||
return (_jsx(RebassButton, __assign({}, props, { ref: function (ref) {
|
||||
buttonRef.current = ref;
|
||||
// props.ref = ref;
|
||||
if (typeof forwardedRef === "function")
|
||||
forwardedRef(ref);
|
||||
else if (forwardedRef)
|
||||
forwardedRef.current = ref;
|
||||
}, onClick: props.onClick, onMouseDown: function () { } })));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,11 +33,11 @@ export function Menu(props) {
|
||||
var hoverTimeout = useRef();
|
||||
var onAction = useCallback(function (e, item) {
|
||||
e === null || e === void 0 ? void 0 : e.stopPropagation();
|
||||
if (onClose)
|
||||
onClose();
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
}
|
||||
if (onClose)
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
var _b = useFocus(items, function (e) {
|
||||
var item = items[focusIndex];
|
||||
|
||||
@@ -11,8 +11,7 @@ var __assign = (this && this.__assign) || function () {
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useRef } from "react";
|
||||
import { Flex, Text } from "rebass";
|
||||
import { Button } from "../button";
|
||||
import { Flex, Text, Button } from "rebass";
|
||||
import { Icon } from "../../toolbar/components/icon";
|
||||
import { Icons } from "../../toolbar/icons";
|
||||
import { useToolbarLocation } from "../../toolbar/stores/toolbar-store";
|
||||
|
||||
@@ -164,6 +164,7 @@ export var CodeBlock = Node.create({
|
||||
toggleCodeBlock: function (attributes) {
|
||||
return function (_a) {
|
||||
var commands = _a.commands;
|
||||
console.log("TOGGLING!");
|
||||
return commands.toggleNode(_this.name, "paragraph", attributes);
|
||||
};
|
||||
},
|
||||
|
||||
@@ -2,21 +2,19 @@ import React from "react";
|
||||
import { NodeView, Decoration, DecorationSource } from "prosemirror-view";
|
||||
import { Node as PMNode } from "prosemirror-model";
|
||||
import { PortalProviderAPI } from "./react-portal-provider";
|
||||
import { EventDispatcher } from "./event-dispatcher";
|
||||
import { ReactNodeViewProps, ReactNodeViewOptions, GetPosNode, ForwardRef, ContentDOM } from "./types";
|
||||
import { Editor, NodeViewRendererProps } from "@tiptap/core";
|
||||
export declare class ReactNodeView<P extends ReactNodeViewProps> implements NodeView {
|
||||
protected readonly editor: Editor;
|
||||
protected readonly getPos: GetPosNode;
|
||||
protected readonly portalProviderAPI: PortalProviderAPI;
|
||||
protected readonly eventDispatcher: EventDispatcher;
|
||||
protected readonly options: ReactNodeViewOptions<P>;
|
||||
private domRef;
|
||||
private contentDOMWrapper?;
|
||||
contentDOM: HTMLElement | undefined;
|
||||
node: PMNode;
|
||||
isDragging: boolean;
|
||||
constructor(node: PMNode, editor: Editor, getPos: GetPosNode, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher, options: ReactNodeViewOptions<P>);
|
||||
portalProviderAPI: PortalProviderAPI;
|
||||
constructor(node: PMNode, editor: Editor, getPos: GetPosNode, options: ReactNodeViewOptions<P>);
|
||||
/**
|
||||
* This method exists to move initialization logic out of the constructor,
|
||||
* so object can be initialized properly before calling render first time.
|
||||
|
||||
@@ -38,15 +38,15 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { NodeSelection } from "prosemirror-state";
|
||||
import { ThemeProvider } from "emotion-theming";
|
||||
var ReactNodeView = /** @class */ (function () {
|
||||
function ReactNodeView(node, editor, getPos, portalProviderAPI, eventDispatcher, options) {
|
||||
function ReactNodeView(node, editor, getPos, options) {
|
||||
var _this = this;
|
||||
this.editor = editor;
|
||||
this.getPos = getPos;
|
||||
this.portalProviderAPI = portalProviderAPI;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.options = options;
|
||||
this.isDragging = false;
|
||||
this.handleRef = function (node) { return _this._handleRef(node); };
|
||||
this.portalProviderAPI = editor.storage
|
||||
.portalProviderAPI;
|
||||
this.node = node;
|
||||
}
|
||||
/**
|
||||
@@ -84,6 +84,7 @@ var ReactNodeView = /** @class */ (function () {
|
||||
};
|
||||
ReactNodeView.prototype.renderReactComponent = function (component) {
|
||||
if (!this.domRef || !component || !this.portalProviderAPI) {
|
||||
console.warn("Cannot render node view", this.editor.storage);
|
||||
return;
|
||||
}
|
||||
this.portalProviderAPI.render(component, this.domRef);
|
||||
@@ -337,6 +338,6 @@ export function createNodeView(component, options) {
|
||||
return function (_a) {
|
||||
var node = _a.node, getPos = _a.getPos, editor = _a.editor;
|
||||
var _getPos = function () { return (typeof getPos === "boolean" ? -1 : getPos()); };
|
||||
return new ReactNodeView(node, editor, _getPos, editor.storage.portalProviderAPI, editor.storage.eventDispatcher, __assign(__assign({}, options), { component: component })).init();
|
||||
return new ReactNodeView(node, editor, _getPos, __assign(__assign({}, options), { component: component })).init();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React from "react";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { EventDispatcher } from "./event-dispatcher";
|
||||
export declare type BasePortalProviderProps = {
|
||||
render: (portalProviderAPI: PortalProviderAPI) => React.ReactChild | JSX.Element | null;
|
||||
};
|
||||
export declare type BasePortalProviderProps = PropsWithChildren<{}>;
|
||||
export declare type Portals = Map<HTMLElement, React.ReactChild>;
|
||||
export declare type PortalRendererState = {
|
||||
portals: Portals;
|
||||
@@ -19,11 +17,12 @@ export declare class PortalProviderAPI extends EventDispatcher {
|
||||
forceUpdate(): void;
|
||||
remove(container: HTMLElement): void;
|
||||
}
|
||||
export declare function usePortalProvider(): PortalProviderAPI | undefined;
|
||||
export declare class PortalProvider extends React.Component<BasePortalProviderProps> {
|
||||
static displayName: string;
|
||||
portalProviderAPI: PortalProviderAPI;
|
||||
constructor(props: BasePortalProviderProps);
|
||||
render(): JSX.Element | React.ReactChild | null;
|
||||
render(): JSX.Element;
|
||||
componentDidUpdate(): void;
|
||||
}
|
||||
export declare class PortalRenderer extends React.Component<{
|
||||
|
||||
@@ -13,6 +13,17 @@ var __extends = (this && this.__extends) || (function () {
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
var __read = (this && this.__read) || function (o, n) {
|
||||
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
||||
if (!m) return o;
|
||||
@@ -29,8 +40,8 @@ var __read = (this && this.__read) || function (o, n) {
|
||||
}
|
||||
return ar;
|
||||
};
|
||||
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
||||
import React from "react";
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import React, { useContext } from "react";
|
||||
import { createPortal, unstable_renderSubtreeIntoContainer, unmountComponentAtNode, } from "react-dom";
|
||||
import { EventDispatcher } from "./event-dispatcher";
|
||||
var PortalProviderAPI = /** @class */ (function (_super) {
|
||||
@@ -72,6 +83,10 @@ var PortalProviderAPI = /** @class */ (function (_super) {
|
||||
return PortalProviderAPI;
|
||||
}(EventDispatcher));
|
||||
export { PortalProviderAPI };
|
||||
var PortalProviderContext = React.createContext(undefined);
|
||||
export function usePortalProvider() {
|
||||
return useContext(PortalProviderContext);
|
||||
}
|
||||
var PortalProvider = /** @class */ (function (_super) {
|
||||
__extends(PortalProvider, _super);
|
||||
function PortalProvider(props) {
|
||||
@@ -80,7 +95,7 @@ var PortalProvider = /** @class */ (function (_super) {
|
||||
return _this;
|
||||
}
|
||||
PortalProvider.prototype.render = function () {
|
||||
return this.props.render(this.portalProviderAPI);
|
||||
return (_jsxs(PortalProviderContext.Provider, __assign({ value: this.portalProviderAPI }, { children: [this.props.children, _jsx(PortalRenderer, { portalProviderAPI: this.portalProviderAPI })] })));
|
||||
};
|
||||
PortalProvider.prototype.componentDidUpdate = function () {
|
||||
this.portalProviderAPI.forceUpdate();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from "react";
|
||||
import { Node as PMNode } from "prosemirror-model";
|
||||
import { PortalProviderAPI } from "./react-portal-provider";
|
||||
import { EventDispatcher } from "./event-dispatcher";
|
||||
import { ReactNodeViewOptions, GetPosNode, SelectionBasedReactNodeViewProps, ForwardRef } from "./types";
|
||||
import { ReactNodeView } from "./react-node-view";
|
||||
import { Editor, NodeViewRendererProps } from "@tiptap/core";
|
||||
@@ -33,7 +31,7 @@ export declare class SelectionBasedNodeView<P extends SelectionBasedReactNodeVie
|
||||
private selectionChangeState;
|
||||
pos: number;
|
||||
posEnd: number | undefined;
|
||||
constructor(node: PMNode, editor: Editor, getPos: GetPosNode, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher, options: ReactNodeViewOptions<P>);
|
||||
constructor(node: PMNode, editor: Editor, getPos: GetPosNode, options: ReactNodeViewOptions<P>);
|
||||
render(props?: P, forwardRef?: ForwardRef): React.ReactElement<any> | null;
|
||||
/**
|
||||
* Update current node's start and end positions.
|
||||
|
||||
@@ -55,8 +55,8 @@ import { ThemeProvider } from "emotion-theming";
|
||||
*/
|
||||
var SelectionBasedNodeView = /** @class */ (function (_super) {
|
||||
__extends(SelectionBasedNodeView, _super);
|
||||
function SelectionBasedNodeView(node, editor, getPos, portalProviderAPI, eventDispatcher, options) {
|
||||
var _this = _super.call(this, node, editor, getPos, portalProviderAPI, eventDispatcher, options) || this;
|
||||
function SelectionBasedNodeView(node, editor, getPos, options) {
|
||||
var _this = _super.call(this, node, editor, getPos, options) || this;
|
||||
_this.pos = -1;
|
||||
_this.isNodeInsideSelection = function (from, to, pos, posEnd) {
|
||||
var _a;
|
||||
@@ -174,6 +174,6 @@ export function createSelectionBasedNodeView(component, options) {
|
||||
return function (_a) {
|
||||
var node = _a.node, getPos = _a.getPos, editor = _a.editor;
|
||||
var _getPos = function () { return (typeof getPos === "boolean" ? -1 : getPos()); };
|
||||
return new SelectionBasedNodeView(node, editor, _getPos, editor.storage.portalProviderAPI, editor.storage.eventDispatcher, __assign(__assign({}, options), { component: component })).init();
|
||||
return new SelectionBasedNodeView(node, editor, _getPos, __assign(__assign({}, options), { component: component })).init();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export function TableNodeView(editor) {
|
||||
__extends(TableNode, _super);
|
||||
function TableNode(node, cellMinWidth) {
|
||||
var _this = _super.call(this, node, editor, function () { return 0; }, // todo
|
||||
editor.storage.portalProviderAPI, editor.storage.eventDispatcher, {
|
||||
{
|
||||
component: TableComponent,
|
||||
shouldUpdate: function (prev, next) {
|
||||
return prev.type === next.type;
|
||||
|
||||
4
packages/editor/dist/index.d.ts
vendored
4
packages/editor/dist/index.d.ts
vendored
@@ -3,10 +3,8 @@ import { EditorOptions } from "@tiptap/react";
|
||||
import Toolbar from "./toolbar";
|
||||
import { Theme } from "@notesnook/theme";
|
||||
import { AttachmentOptions } from "./extensions/attachment";
|
||||
import { PortalProviderAPI } from "./extensions/react";
|
||||
declare const useTiptap: (options?: Partial<EditorOptions & AttachmentOptions & {
|
||||
theme: Theme;
|
||||
portalProviderAPI: PortalProviderAPI;
|
||||
}>, deps?: React.DependencyList) => import("@tiptap/react").Editor | null;
|
||||
}>, deps?: import("react").DependencyList) => import("@tiptap/react").Editor | null;
|
||||
export { useTiptap, Toolbar };
|
||||
export * from "./extensions/react";
|
||||
|
||||
25
packages/editor/dist/index.js
vendored
25
packages/editor/dist/index.js
vendored
@@ -53,7 +53,7 @@ import { EmbedNode } from "./extensions/embed";
|
||||
import { CodeBlock } from "./extensions/code-block";
|
||||
import { ListItem } from "./extensions/list-item";
|
||||
import { Link } from "./extensions/link";
|
||||
import { EventDispatcher, NodeViewSelectionNotifier, } from "./extensions/react";
|
||||
import { NodeViewSelectionNotifier, usePortalProvider, } from "./extensions/react";
|
||||
import { OutlineList } from "./extensions/outline-list";
|
||||
import { OutlineListItem } from "./extensions/outline-list-item";
|
||||
import { Table } from "./extensions/table";
|
||||
@@ -64,8 +64,9 @@ EditorView.prototype.updateState = function updateState(state) {
|
||||
};
|
||||
var useTiptap = function (options, deps) {
|
||||
if (options === void 0) { options = {}; }
|
||||
var theme = options.theme, onCreate = options.onCreate, onDownloadAttachment = options.onDownloadAttachment, onOpenAttachmentPicker = options.onOpenAttachmentPicker, portalProviderAPI = options.portalProviderAPI, restOptions = __rest(options, ["theme", "onCreate", "onDownloadAttachment", "onOpenAttachmentPicker", "portalProviderAPI"]);
|
||||
var eventDispatcher = useMemo(function () { return new EventDispatcher(); }, []);
|
||||
if (deps === void 0) { deps = []; }
|
||||
var theme = options.theme, onDownloadAttachment = options.onDownloadAttachment, onOpenAttachmentPicker = options.onOpenAttachmentPicker, restOptions = __rest(options, ["theme", "onDownloadAttachment", "onOpenAttachmentPicker"]);
|
||||
var PortalProviderAPI = usePortalProvider();
|
||||
var defaultOptions = useMemo(function () { return ({
|
||||
extensions: [
|
||||
NodeViewSelectionNotifier,
|
||||
@@ -128,27 +129,15 @@ var useTiptap = function (options, deps) {
|
||||
OutlineList,
|
||||
ListItem,
|
||||
],
|
||||
onCreate: function (_a) {
|
||||
onBeforeCreate: function (_a) {
|
||||
var editor = _a.editor;
|
||||
if (theme) {
|
||||
editor.storage.theme = theme;
|
||||
}
|
||||
if (portalProviderAPI)
|
||||
editor.storage.portalProviderAPI = portalProviderAPI;
|
||||
if (eventDispatcher)
|
||||
editor.storage.eventDispatcher = eventDispatcher;
|
||||
if (onCreate)
|
||||
onCreate({ editor: editor });
|
||||
editor.storage.portalProviderAPI = PortalProviderAPI;
|
||||
},
|
||||
injectCSS: false,
|
||||
}); }, [
|
||||
theme,
|
||||
onCreate,
|
||||
onDownloadAttachment,
|
||||
onOpenAttachmentPicker,
|
||||
portalProviderAPI,
|
||||
eventDispatcher,
|
||||
]);
|
||||
}); }, [theme, onDownloadAttachment, onOpenAttachmentPicker, PortalProviderAPI]);
|
||||
var editor = useEditor(__assign(__assign({}, defaultOptions), restOptions), deps);
|
||||
/**
|
||||
* Add editor to global for use in React Native.
|
||||
|
||||
@@ -98,7 +98,7 @@ export function TablePopup(props) {
|
||||
columns: cellLocation.column,
|
||||
rows: cellLocation.row,
|
||||
});
|
||||
} })); }) })), _jsxs(Flex, __assign({ sx: {
|
||||
} }, index)); }) })), _jsxs(Flex, __assign({ sx: {
|
||||
display: ["flex", "none", "none"],
|
||||
my: 1,
|
||||
alignItems: "center",
|
||||
|
||||
2
packages/editor/dist/toolbar/tools/block.js
vendored
2
packages/editor/dist/toolbar/tools/block.js
vendored
@@ -37,7 +37,7 @@ import { showPopup } from "../../components/popup-presenter";
|
||||
import { ImageUploadPopup } from "../popups/image-upload";
|
||||
import { Button } from "../../components/button";
|
||||
export function InsertBlock(props) {
|
||||
var buttonRef = useRef();
|
||||
var buttonRef = useRef(null);
|
||||
var _a = __read(useState(false), 2), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var toolbarLocation = useToolbarLocation();
|
||||
var isMobile = useIsMobile();
|
||||
|
||||
@@ -1,94 +1,41 @@
|
||||
import React, { useCallback, useRef } from "react";
|
||||
import { forwardRef, useCallback, useRef } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { Button as RebassButton, ButtonProps } from "rebass";
|
||||
|
||||
export function Button(props: ButtonProps) {
|
||||
const buttonRef = useRef<HTMLButtonElement>();
|
||||
const touchStartTime = useRef(0);
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
(props: ButtonProps, forwardedRef) => {
|
||||
const buttonRef = useRef<HTMLButtonElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!buttonRef.current) return;
|
||||
useEffect(() => {
|
||||
if (!buttonRef.current) return;
|
||||
|
||||
buttonRef.current.addEventListener("mousedown", onMouseDown, {
|
||||
passive: false,
|
||||
capture: true,
|
||||
});
|
||||
|
||||
// buttonRef.current.addEventListener("touchmove", onTouchMove, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
|
||||
// buttonRef.current.addEventListener("touchend", onTouchEnd, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
|
||||
// buttonRef.current.addEventListener("touchstart", onTouchStart, {
|
||||
// passive: false,
|
||||
// capture: true,
|
||||
// });
|
||||
|
||||
return () => {
|
||||
buttonRef.current?.removeEventListener("mousedown", onMouseDown, {
|
||||
buttonRef.current.addEventListener("mousedown", onMouseDown, {
|
||||
passive: false,
|
||||
capture: true,
|
||||
});
|
||||
// buttonRef.current?.removeEventListener("touchmove", onTouchMove, {
|
||||
// capture: true,
|
||||
// });
|
||||
|
||||
// buttonRef.current?.removeEventListener("touchend", onTouchEnd, {
|
||||
// capture: true,
|
||||
// });
|
||||
return () => {
|
||||
buttonRef.current?.removeEventListener("mousedown", onMouseDown, {
|
||||
capture: true,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
// buttonRef.current?.removeEventListener("touchstart", onTouchStart, {
|
||||
// capture: true,
|
||||
// });
|
||||
};
|
||||
}, []);
|
||||
const onMouseDown = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
}, []);
|
||||
|
||||
const onMouseDown = useCallback((e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
}, []);
|
||||
|
||||
// const onTouchEnd = useCallback((e) => {
|
||||
// e.preventDefault();
|
||||
// const now = Date.now();
|
||||
// setTimeout(() => {
|
||||
// console.log(now, touchStartTime.current);
|
||||
// if (touchStartTime.current === 0) return;
|
||||
// if (now - touchStartTime.current > 300) return;
|
||||
// //@ts-ignore
|
||||
// props.onClick(e);
|
||||
// }, 1);
|
||||
// }, []);
|
||||
|
||||
// const onTouchStart = useCallback((e) => {
|
||||
// touchStartTime.current = Date.now();
|
||||
// console.log("HELLO!");
|
||||
// e.preventDefault();
|
||||
// }, []);
|
||||
|
||||
// const onTouchMove = useCallback((e) => {
|
||||
// console.log("HELLO!");
|
||||
// touchStartTime.current = 0;
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<RebassButton
|
||||
{...props}
|
||||
ref={(ref) => {
|
||||
buttonRef.current = ref;
|
||||
// props.ref = ref;
|
||||
}}
|
||||
onClick={props.onClick}
|
||||
onMouseDown={() => {}}
|
||||
// onTouchEnd={() => {}}
|
||||
// onTouchMove={() => {}}
|
||||
// // {
|
||||
// // touchStartTime.current = 0;
|
||||
// // }}
|
||||
// onTouchStart={() => {}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<RebassButton
|
||||
{...props}
|
||||
ref={(ref) => {
|
||||
buttonRef.current = ref;
|
||||
if (typeof forwardedRef === "function") forwardedRef(ref);
|
||||
else if (forwardedRef) forwardedRef.current = ref;
|
||||
}}
|
||||
onClick={props.onClick}
|
||||
onMouseDown={() => {}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -26,10 +26,11 @@ export function Menu(props: MenuProps) {
|
||||
const onAction = useCallback(
|
||||
(e, item) => {
|
||||
e?.stopPropagation();
|
||||
if (onClose) onClose();
|
||||
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
}
|
||||
if (onClose) onClose();
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useRef } from "react";
|
||||
import { Flex, Text } from "rebass";
|
||||
import { Button } from "../button";
|
||||
import { Flex, Text, Button } from "rebass";
|
||||
import { Icon } from "../../toolbar/components/icon";
|
||||
import { Icons } from "../../toolbar/icons";
|
||||
import { useToolbarLocation } from "../../toolbar/stores/toolbar-store";
|
||||
|
||||
@@ -207,6 +207,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
|
||||
toggleCodeBlock:
|
||||
(attributes) =>
|
||||
({ commands }) => {
|
||||
console.log("TOGGLING!");
|
||||
return commands.toggleNode(this.name, "paragraph", attributes);
|
||||
},
|
||||
changeCodeBlockIndentation:
|
||||
|
||||
@@ -22,15 +22,16 @@ export class ReactNodeView<P extends ReactNodeViewProps> implements NodeView {
|
||||
contentDOM: HTMLElement | undefined;
|
||||
node: PMNode;
|
||||
isDragging = false;
|
||||
portalProviderAPI: PortalProviderAPI;
|
||||
|
||||
constructor(
|
||||
node: PMNode,
|
||||
protected readonly editor: Editor,
|
||||
protected readonly getPos: GetPosNode,
|
||||
protected readonly portalProviderAPI: PortalProviderAPI,
|
||||
protected readonly eventDispatcher: EventDispatcher,
|
||||
protected readonly options: ReactNodeViewOptions<P>
|
||||
) {
|
||||
this.portalProviderAPI = editor.storage
|
||||
.portalProviderAPI as PortalProviderAPI;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@@ -76,6 +77,7 @@ export class ReactNodeView<P extends ReactNodeViewProps> implements NodeView {
|
||||
component: () => React.ReactElement<any> | null
|
||||
) {
|
||||
if (!this.domRef || !component || !this.portalProviderAPI) {
|
||||
console.warn("Cannot render node view", this.editor.storage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -416,17 +418,10 @@ export function createNodeView<TProps extends ReactNodeViewProps>(
|
||||
return ({ node, getPos, editor }: NodeViewRendererProps) => {
|
||||
const _getPos = () => (typeof getPos === "boolean" ? -1 : getPos());
|
||||
|
||||
return new ReactNodeView<TProps>(
|
||||
node,
|
||||
editor,
|
||||
_getPos,
|
||||
editor.storage.portalProviderAPI,
|
||||
editor.storage.eventDispatcher,
|
||||
{
|
||||
...options,
|
||||
component,
|
||||
}
|
||||
).init();
|
||||
return new ReactNodeView<TProps>(node, editor, _getPos, {
|
||||
...options,
|
||||
component,
|
||||
}).init();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { PropsWithChildren, useContext } from "react";
|
||||
import {
|
||||
createPortal,
|
||||
unstable_renderSubtreeIntoContainer,
|
||||
@@ -6,11 +6,7 @@ import {
|
||||
} from "react-dom";
|
||||
import { EventDispatcher } from "./event-dispatcher";
|
||||
|
||||
export type BasePortalProviderProps = {
|
||||
render: (
|
||||
portalProviderAPI: PortalProviderAPI
|
||||
) => React.ReactChild | JSX.Element | null;
|
||||
};
|
||||
export type BasePortalProviderProps = PropsWithChildren<{}>;
|
||||
|
||||
export type Portals = Map<HTMLElement, React.ReactChild>;
|
||||
|
||||
@@ -71,6 +67,12 @@ export class PortalProviderAPI extends EventDispatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
const PortalProviderContext = React.createContext<
|
||||
PortalProviderAPI | undefined
|
||||
>(undefined);
|
||||
export function usePortalProvider() {
|
||||
return useContext(PortalProviderContext);
|
||||
}
|
||||
|
||||
export class PortalProvider extends React.Component<BasePortalProviderProps> {
|
||||
static displayName = "PortalProvider";
|
||||
@@ -83,7 +85,12 @@ export class PortalProvider extends React.Component<BasePortalProviderProps> {
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.render(this.portalProviderAPI);
|
||||
return (
|
||||
<PortalProviderContext.Provider value={this.portalProviderAPI}>
|
||||
{this.props.children}
|
||||
<PortalRenderer portalProviderAPI={this.portalProviderAPI} />
|
||||
</PortalProviderContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
||||
@@ -57,11 +57,9 @@ export class SelectionBasedNodeView<
|
||||
node: PMNode,
|
||||
editor: Editor,
|
||||
getPos: GetPosNode,
|
||||
portalProviderAPI: PortalProviderAPI,
|
||||
eventDispatcher: EventDispatcher,
|
||||
options: ReactNodeViewOptions<P>
|
||||
) {
|
||||
super(node, editor, getPos, portalProviderAPI, eventDispatcher, options);
|
||||
super(node, editor, getPos, options);
|
||||
|
||||
this.updatePos();
|
||||
|
||||
@@ -251,16 +249,9 @@ export function createSelectionBasedNodeView<
|
||||
) {
|
||||
return ({ node, getPos, editor }: NodeViewRendererProps) => {
|
||||
const _getPos = () => (typeof getPos === "boolean" ? -1 : getPos());
|
||||
return new SelectionBasedNodeView(
|
||||
node,
|
||||
editor,
|
||||
_getPos,
|
||||
editor.storage.portalProviderAPI,
|
||||
editor.storage.eventDispatcher,
|
||||
{
|
||||
...options,
|
||||
component,
|
||||
}
|
||||
).init();
|
||||
return new SelectionBasedNodeView(node, editor, _getPos, {
|
||||
...options,
|
||||
component,
|
||||
}).init();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,8 +77,6 @@ export function TableNodeView(editor: Editor) {
|
||||
node,
|
||||
editor,
|
||||
() => 0, // todo
|
||||
editor.storage.portalProviderAPI,
|
||||
editor.storage.eventDispatcher,
|
||||
{
|
||||
component: TableComponent,
|
||||
shouldUpdate: (prev, next) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import Placeholder from "@tiptap/extension-placeholder";
|
||||
import Underline from "@tiptap/extension-underline";
|
||||
import { EditorOptions, useEditor } from "@tiptap/react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { useMemo } from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { EditorView } from "prosemirror-view";
|
||||
import Toolbar from "./toolbar";
|
||||
import TextAlign from "@tiptap/extension-text-align";
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
PortalProviderAPI,
|
||||
EventDispatcher,
|
||||
NodeViewSelectionNotifier,
|
||||
usePortalProvider,
|
||||
} from "./extensions/react";
|
||||
import { OutlineList } from "./extensions/outline-list";
|
||||
import { OutlineListItem } from "./extensions/outline-list-item";
|
||||
@@ -47,21 +48,16 @@ EditorView.prototype.updateState = function updateState(state) {
|
||||
};
|
||||
|
||||
const useTiptap = (
|
||||
options: Partial<
|
||||
EditorOptions &
|
||||
AttachmentOptions & { theme: Theme; portalProviderAPI: PortalProviderAPI }
|
||||
> = {},
|
||||
deps?: React.DependencyList
|
||||
options: Partial<EditorOptions & AttachmentOptions & { theme: Theme }> = {},
|
||||
deps: React.DependencyList = []
|
||||
) => {
|
||||
const {
|
||||
theme,
|
||||
onCreate,
|
||||
onDownloadAttachment,
|
||||
onOpenAttachmentPicker,
|
||||
portalProviderAPI,
|
||||
...restOptions
|
||||
} = options;
|
||||
const eventDispatcher = useMemo(() => new EventDispatcher(), []);
|
||||
const PortalProviderAPI = usePortalProvider();
|
||||
|
||||
const defaultOptions = useMemo<Partial<EditorOptions>>(
|
||||
() => ({
|
||||
@@ -127,27 +123,15 @@ const useTiptap = (
|
||||
OutlineList,
|
||||
ListItem,
|
||||
],
|
||||
onCreate: ({ editor }) => {
|
||||
onBeforeCreate: ({ editor }) => {
|
||||
if (theme) {
|
||||
editor.storage.theme = theme;
|
||||
}
|
||||
|
||||
if (portalProviderAPI)
|
||||
editor.storage.portalProviderAPI = portalProviderAPI;
|
||||
if (eventDispatcher) editor.storage.eventDispatcher = eventDispatcher;
|
||||
|
||||
if (onCreate) onCreate({ editor });
|
||||
editor.storage.portalProviderAPI = PortalProviderAPI;
|
||||
},
|
||||
injectCSS: false,
|
||||
}),
|
||||
[
|
||||
theme,
|
||||
onCreate,
|
||||
onDownloadAttachment,
|
||||
onOpenAttachmentPicker,
|
||||
portalProviderAPI,
|
||||
eventDispatcher,
|
||||
]
|
||||
[theme, onDownloadAttachment, onOpenAttachmentPicker, PortalProviderAPI]
|
||||
);
|
||||
|
||||
const editor = useEditor(
|
||||
|
||||
@@ -81,6 +81,7 @@ export function TablePopup(props: TablePopupProps) {
|
||||
.fill(0)
|
||||
.map((_, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
data-index={index}
|
||||
height={cellSize || 15}
|
||||
sx={{
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ImageUploadPopup } from "../popups/image-upload";
|
||||
import { Button } from "../../components/button";
|
||||
|
||||
export function InsertBlock(props: ToolProps) {
|
||||
const buttonRef = useRef<HTMLButtonElement | null>();
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const toolbarLocation = useToolbarLocation();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
Reference in New Issue
Block a user