From 5841943778854865c8b1075138b1a633769c31ad Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 27 Jun 2022 09:00:36 +0500 Subject: [PATCH] feat: improve popups ui for web --- .../editor/dist/components/menu/usefocus.d.ts | 1 + .../dist/components/popuppresenter/index.js | 1 - .../editor/dist/extensions/table/actions.js | 1 - .../editor/dist/extensions/table/table.d.ts | 57 +--- .../editor/dist/extensions/table/table.js | 204 +----------- packages/editor/dist/index.d.ts | 1 + .../editor/dist/toolbar/components/popup.d.ts | 7 + .../editor/dist/toolbar/components/popup.js | 8 +- .../dist/toolbar/components/toolbutton.d.ts | 4 +- .../dist/toolbar/components/toolbutton.js | 1 - .../dist/toolbar/popups/embedpopup.d.ts | 2 +- .../editor/dist/toolbar/popups/embedpopup.js | 43 +-- .../editor/dist/toolbar/popups/imageupload.js | 100 +++--- .../editor/dist/toolbar/tooldefinitions.js | 2 +- packages/editor/dist/toolbar/tools/block.js | 6 +- packages/editor/package-lock.json | 142 ++------- packages/editor/package.json | 2 +- .../src/components/popup-presenter/index.tsx | 1 - .../editor/src/extensions/table/actions.ts | 1 - .../editor/src/extensions/table/component.tsx | 24 +- packages/editor/src/extensions/table/table.ts | 292 +----------------- .../src/extensions/table/utils/createCell.ts | 17 - .../src/extensions/table/utils/createTable.ts | 45 --- .../utils/deleteTableWhenAllCellsSelected.ts | 36 --- .../table/utils/getTableNodeTypes.ts | 21 -- .../extensions/table/utils/isCellSelection.ts | 5 - .../editor/src/toolbar/components/popup.tsx | 37 ++- .../src/toolbar/components/tool-button.tsx | 1 - .../editor/src/toolbar/popups/embed-popup.tsx | 14 +- .../src/toolbar/popups/image-upload.tsx | 104 +++++-- .../editor/src/toolbar/tool-definitions.ts | 2 +- packages/editor/src/toolbar/tools/block.tsx | 2 +- 32 files changed, 253 insertions(+), 931 deletions(-) delete mode 100644 packages/editor/src/extensions/table/utils/createCell.ts delete mode 100644 packages/editor/src/extensions/table/utils/createTable.ts delete mode 100644 packages/editor/src/extensions/table/utils/deleteTableWhenAllCellsSelected.ts delete mode 100644 packages/editor/src/extensions/table/utils/getTableNodeTypes.ts delete mode 100644 packages/editor/src/extensions/table/utils/isCellSelection.ts diff --git a/packages/editor/dist/components/menu/usefocus.d.ts b/packages/editor/dist/components/menu/usefocus.d.ts index 66f324efc..36b4ee2ca 100644 --- a/packages/editor/dist/components/menu/usefocus.d.ts +++ b/packages/editor/dist/components/menu/usefocus.d.ts @@ -1,3 +1,4 @@ +/// import { MenuItem } from "./types"; export declare function useFocus(items: MenuItem[], onAction: (event: KeyboardEvent) => void, onClose: (event: KeyboardEvent) => void): { focusIndex: number; diff --git a/packages/editor/dist/components/popuppresenter/index.js b/packages/editor/dist/components/popuppresenter/index.js index 63a438a54..bb2bf42b2 100644 --- a/packages/editor/dist/components/popuppresenter/index.js +++ b/packages/editor/dist/components/popuppresenter/index.js @@ -43,7 +43,6 @@ function _PopupPresenter(props) { var popupPosition = getPosition(popup, position); popup.style.top = popupPosition.top + "px"; popup.style.left = popupPosition.left + "px"; - console.log("popup", popupPosition); }, [position]); useEffect(function () { repositionPopup(); diff --git a/packages/editor/dist/extensions/table/actions.js b/packages/editor/dist/extensions/table/actions.js index 2774ab1fe..0b0d49ac9 100644 --- a/packages/editor/dist/extensions/table/actions.js +++ b/packages/editor/dist/extensions/table/actions.js @@ -57,7 +57,6 @@ function getColumnCells(_a, col) { continue; cells.push({ cell: cell, pos: pos }); row += cell.attrs.rowspan; - console.log(cell.textContent); } return cells; } diff --git a/packages/editor/dist/extensions/table/table.d.ts b/packages/editor/dist/extensions/table/table.d.ts index 14bae9647..e5a29b0de 100644 --- a/packages/editor/dist/extensions/table/table.d.ts +++ b/packages/editor/dist/extensions/table/table.d.ts @@ -1,55 +1,2 @@ -import { Node, ParentConfig } from "@tiptap/core"; -import { NodeView } from "prosemirror-view"; -export interface TableOptions { - HTMLAttributes: Record; - resizable: boolean; - handleWidth: number; - cellMinWidth: number; - View: NodeView; - lastColumnResizable: boolean; - allowTableNodeSelection: boolean; -} -declare module "@tiptap/core" { - interface Commands { - table: { - insertTable: (options?: { - rows?: number; - cols?: number; - withHeaderRow?: boolean; - }) => ReturnType; - addColumnBefore: () => ReturnType; - addColumnAfter: () => ReturnType; - deleteColumn: () => ReturnType; - addRowBefore: () => ReturnType; - addRowAfter: () => ReturnType; - deleteRow: () => ReturnType; - deleteTable: () => ReturnType; - mergeCells: () => ReturnType; - splitCell: () => ReturnType; - toggleHeaderColumn: () => ReturnType; - toggleHeaderRow: () => ReturnType; - toggleHeaderCell: () => ReturnType; - mergeOrSplit: () => ReturnType; - setCellAttribute: (name: string, value: any) => ReturnType; - goToNextCell: () => ReturnType; - goToPreviousCell: () => ReturnType; - fixTables: () => ReturnType; - setCellSelection: (position: { - anchorCell: number; - headCell?: number; - }) => ReturnType; - }; - } - interface NodeConfig { - /** - * Table Role - */ - tableRole?: string | ((this: { - name: string; - options: Options; - storage: Storage; - parent: ParentConfig>["tableRole"]; - }) => string); - } -} -export declare const Table: Node; +import { TableOptions } from "@tiptap/extension-table"; +export declare const Table: import("@tiptap/core").Node; diff --git a/packages/editor/dist/extensions/table/table.js b/packages/editor/dist/extensions/table/table.js index 45cffd4d3..1b0810ee3 100644 --- a/packages/editor/dist/extensions/table/table.js +++ b/packages/editor/dist/extensions/table/table.js @@ -23,198 +23,10 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { } return to.concat(ar || Array.prototype.slice.call(from)); }; -import { callOrReturn, getExtensionField, mergeAttributes, Node, } from "@tiptap/core"; -import { TextSelection } from "prosemirror-state"; -import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, CellSelection, columnResizing, deleteColumn, deleteRow, deleteTable, fixTables, goToNextCell, mergeCells, setCellAttr, splitCell, tableEditing, toggleHeader, toggleHeaderCell, } from "prosemirror-tables"; +import { Table as TiptapTable } from "@tiptap/extension-table"; +import { columnResizing, tableEditing } from "prosemirror-tables"; import { TableNodeView } from "./component"; -import { createTable } from "./utils/createTable"; -import { deleteTableWhenAllCellsSelected } from "./utils/deleteTableWhenAllCellsSelected"; -export var Table = Node.create({ - name: "table", - // @ts-ignore - addOptions: function () { - return { - HTMLAttributes: {}, - resizable: false, - handleWidth: 5, - cellMinWidth: 25, - // TODO: fix - View: null, - lastColumnResizable: true, - allowTableNodeSelection: false, - }; - }, - content: "tableRow+", - tableRole: "table", - isolating: true, - group: "block", - parseHTML: function () { - return [{ tag: "table" }]; - }, - renderHTML: function (_a) { - var HTMLAttributes = _a.HTMLAttributes; - return [ - "table", - mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), - ["tbody", 0], - ]; - }, - addCommands: function () { - return { - insertTable: function (_a) { - var _b = _a === void 0 ? {} : _a, _c = _b.rows, rows = _c === void 0 ? 3 : _c, _d = _b.cols, cols = _d === void 0 ? 3 : _d, _e = _b.withHeaderRow, withHeaderRow = _e === void 0 ? true : _e; - return function (_a) { - var tr = _a.tr, dispatch = _a.dispatch, editor = _a.editor; - var node = createTable(editor.schema, rows, cols, withHeaderRow); - if (dispatch) { - var offset = tr.selection.anchor + 1; - tr.replaceSelectionWith(node) - .scrollIntoView() - .setSelection(TextSelection.near(tr.doc.resolve(offset))); - } - return true; - }; - }, - addColumnBefore: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return addColumnBefore(state, dispatch); - }; - }, - addColumnAfter: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return addColumnAfter(state, dispatch); - }; - }, - deleteColumn: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return deleteColumn(state, dispatch); - }; - }, - addRowBefore: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return addRowBefore(state, dispatch); - }; - }, - addRowAfter: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return addRowAfter(state, dispatch); - }; - }, - deleteRow: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return deleteRow(state, dispatch); - }; - }, - deleteTable: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return deleteTable(state, dispatch); - }; - }, - mergeCells: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return mergeCells(state, dispatch); - }; - }, - splitCell: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return splitCell(state, dispatch); - }; - }, - toggleHeaderColumn: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return toggleHeader("column")(state, dispatch); - }; - }, - toggleHeaderRow: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return toggleHeader("row")(state, dispatch); - }; - }, - toggleHeaderCell: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return toggleHeaderCell(state, dispatch); - }; - }, - mergeOrSplit: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - if (mergeCells(state, dispatch)) { - return true; - } - return splitCell(state, dispatch); - }; - }, - setCellAttribute: function (name, value) { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return setCellAttr(name, value)(state, dispatch); - }; - }, - goToNextCell: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return goToNextCell(1)(state, dispatch); - }; - }, - goToPreviousCell: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - return goToNextCell(-1)(state, dispatch); - }; - }, - fixTables: function () { - return function (_a) { - var state = _a.state, dispatch = _a.dispatch; - if (dispatch) { - fixTables(state); - } - return true; - }; - }, - setCellSelection: function (position) { - return function (_a) { - var tr = _a.tr, dispatch = _a.dispatch; - if (dispatch) { - var selection = CellSelection.create(tr.doc, position.anchorCell, position.headCell); - // @ts-ignore - tr.setSelection(selection); - } - return true; - }; - }, - }; - }, - addKeyboardShortcuts: function () { - var _this = this; - return { - Tab: function () { - if (_this.editor.commands.goToNextCell()) { - return true; - } - if (!_this.editor.can().addRowAfter()) { - return false; - } - return _this.editor.chain().addRowAfter().goToNextCell().run(); - }, - "Shift-Tab": function () { return _this.editor.commands.goToPreviousCell(); }, - Backspace: deleteTableWhenAllCellsSelected, - "Mod-Backspace": deleteTableWhenAllCellsSelected, - Delete: deleteTableWhenAllCellsSelected, - "Mod-Delete": deleteTableWhenAllCellsSelected, - }; - }, +export var Table = TiptapTable.extend({ addProseMirrorPlugins: function () { var isResizable = this.options.resizable && this.editor.isEditable; return __spreadArray(__spreadArray([], __read((isResizable @@ -234,14 +46,4 @@ export var Table = Node.create({ }), ], false); }, - extendNodeSchema: function (extension) { - var context = { - name: extension.name, - options: extension.options, - storage: extension.storage, - }; - return { - tableRole: callOrReturn(getExtensionField(extension, "tableRole", context)), - }; - }, }); diff --git a/packages/editor/dist/index.d.ts b/packages/editor/dist/index.d.ts index 93faa0581..204080ab2 100644 --- a/packages/editor/dist/index.d.ts +++ b/packages/editor/dist/index.d.ts @@ -1,3 +1,4 @@ +/// import "./extensions"; import { EditorOptions } from "@tiptap/react"; import Toolbar from "./toolbar"; diff --git a/packages/editor/dist/toolbar/components/popup.d.ts b/packages/editor/dist/toolbar/components/popup.d.ts index efb36e4e5..49820f7e5 100644 --- a/packages/editor/dist/toolbar/components/popup.d.ts +++ b/packages/editor/dist/toolbar/components/popup.d.ts @@ -1,6 +1,13 @@ import { PropsWithChildren } from "react"; +declare type Action = { + title: string; + onClick: () => void; + loading?: boolean; +}; export declare type PopupProps = { title?: string; onClose: () => void; + action?: Action; }; export declare function Popup(props: PropsWithChildren): JSX.Element; +export {}; diff --git a/packages/editor/dist/toolbar/components/popup.js b/packages/editor/dist/toolbar/components/popup.js index 4c57b3efb..a74b4734f 100644 --- a/packages/editor/dist/toolbar/components/popup.js +++ b/packages/editor/dist/toolbar/components/popup.js @@ -15,7 +15,7 @@ import { Icon } from "./icon"; import { Icons } from "../icons"; import { DesktopOnly, MobileOnly } from "../../components/responsive"; export function Popup(props) { - var title = props.title, onClose = props.onClose, children = props.children; + var title = props.title, onClose = props.onClose, action = props.action, children = props.children; return (_jsxs(_Fragment, { children: [_jsx(DesktopOnly, { children: _jsxs(Flex, __assign({ sx: { overflow: "hidden", bg: "background", @@ -25,10 +25,8 @@ export function Popup(props) { boxShadow: "menu", minWidth: 200, } }, { children: [_jsxs(Flex, __assign({ className: "movable", sx: { - bg: "bgSecondary", justifyContent: "space-between", alignItems: "center", - p: 1, - mb: 1, - } }, { children: [_jsx(Text, __assign({ variant: "body" }, { children: title })), _jsx(Button, __assign({ variant: "tool", sx: { p: 0, bg: "transparent" }, onClick: onClose }, { children: _jsx(Icon, { path: Icons.close, size: 16 }) }))] })), children] })) }), _jsx(MobileOnly, { children: children })] })); + p: 2, + } }, { children: [_jsx(Text, __assign({ variant: "title" }, { children: title })), _jsx(Button, __assign({ variant: "tool", sx: { p: 0, bg: "transparent" }, onClick: onClose }, { children: _jsx(Icon, { path: Icons.close, size: "big" }) }))] })), children, action && (_jsx(Flex, __assign({ sx: { justifyContent: "end" }, bg: "bgSecondary", p: 1, px: 2, mt: 2 }, { children: _jsx(Button, __assign({ variant: "dialog", onClick: action.loading ? undefined : action.onClick, disabled: action.loading }, { children: action.loading ? (_jsx(Icon, { path: Icons.loading, rotate: true, size: "medium" })) : (action.title) })) })))] })) }), _jsx(MobileOnly, { children: children })] })); } diff --git a/packages/editor/dist/toolbar/components/toolbutton.d.ts b/packages/editor/dist/toolbar/components/toolbutton.d.ts index 9040ee68a..3211820e0 100644 --- a/packages/editor/dist/toolbar/components/toolbutton.d.ts +++ b/packages/editor/dist/toolbar/components/toolbutton.d.ts @@ -14,8 +14,8 @@ export declare type ToolButtonProps = ButtonProps & { }; export declare const ToolButton: React.NamedExoticComponent | undefined; variant?: ToolButtonVariant | undefined; diff --git a/packages/editor/dist/toolbar/components/toolbutton.js b/packages/editor/dist/toolbar/components/toolbutton.js index 37db47a16..23a40379b 100644 --- a/packages/editor/dist/toolbar/components/toolbutton.js +++ b/packages/editor/dist/toolbar/components/toolbutton.js @@ -27,7 +27,6 @@ import { Button } from "../../components/button"; import { Icon } from "./icon"; export var ToolButton = React.memo(function ToolButton(props) { var id = props.id, icon = props.icon, iconSize = props.iconSize, iconColor = props.iconColor, toggled = props.toggled, sx = props.sx, buttonRef = props.buttonRef, _a = props.variant, variant = _a === void 0 ? "normal" : _a, buttonProps = __rest(props, ["id", "icon", "iconSize", "iconColor", "toggled", "sx", "buttonRef", "variant"]); - console.log("rerendering", props.title); return (_jsx(Button, __assign({ ref: buttonRef, tabIndex: -1, id: "tool-".concat(id || icon), sx: __assign({ flexShrink: 0, p: variant === "small" ? "small" : 1, borderRadius: variant === "small" ? "small" : "default", m: 0, bg: toggled ? "hover" : "transparent", mr: variant === "small" ? 0 : 1, ":hover": { bg: ["transparent", "hover"] }, ":active": { bg: "hover" }, ":last-of-type": { mr: 0, } }, sx), onMouseDown: function (e) { return e.preventDefault(); } }, buttonProps, { children: _jsx(Icon, { path: Icons[icon], color: iconColor || "icon", size: iconSize || (variant === "small" ? "medium" : "big") }) }))); diff --git a/packages/editor/dist/toolbar/popups/embedpopup.d.ts b/packages/editor/dist/toolbar/popups/embedpopup.d.ts index 384597e54..04e4e1dd6 100644 --- a/packages/editor/dist/toolbar/popups/embedpopup.d.ts +++ b/packages/editor/dist/toolbar/popups/embedpopup.d.ts @@ -2,7 +2,7 @@ import { Embed, EmbedSizeOptions } from "../../extensions/embed"; export declare type EmbedPopupProps = { onClose: (embed?: Embed) => void; - title?: string; + title: string; embed?: Embed; onSizeChanged?: (size: EmbedSizeOptions) => void; onSourceChanged?: (src: string) => void; diff --git a/packages/editor/dist/toolbar/popups/embedpopup.js b/packages/editor/dist/toolbar/popups/embedpopup.js index c7eed62bd..c5db2f8e2 100644 --- a/packages/editor/dist/toolbar/popups/embedpopup.js +++ b/packages/editor/dist/toolbar/popups/embedpopup.js @@ -26,11 +26,10 @@ var __read = (this && this.__read) || function (o, n) { return ar; }; import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime"; -import { Button, Flex, Text } from "rebass"; +import { Flex, Text } from "rebass"; import { useCallback, useEffect, useState } from "react"; import { Popup } from "../components/popup"; import { Input, Textarea } from "@rebass/forms"; -import { convertUrlToEmbedUrl } from "@social-embed/lib"; import { InlineInput } from "../../components/inline-input"; import { Tabs, Tab } from "../../components/tabs"; export function EmbedPopup(props) { @@ -63,51 +62,17 @@ export function EmbedPopup(props) { useEffect(function () { onSourceChanged && onSourceChanged(src); }, [onSourceChanged, src]); - return (_jsx(Popup, __assign({ title: title, onClose: function () { return onClose(); } }, { children: _jsxs(Flex, __assign({ sx: { flexDirection: "column", width: ["auto", 300] } }, { children: [error && (_jsxs(Text, __assign({ variant: "error", sx: { + return (_jsx(Popup, __assign({ title: title, onClose: function () { return onClose(); }, action: { title: title, onClick: function () { return onClose(); } } }, { children: _jsxs(Flex, __assign({ sx: { flexDirection: "column", width: ["auto", 300] } }, { children: [error && (_jsxs(Text, __assign({ variant: "error", sx: { bg: "errorBg", color: "error", p: 1, borderRadius: "default", - } }, { children: ["Error: ", error] }))), _jsxs(Tabs, __assign({ activeIndex: 0, containerProps: { sx: { mx: 1, mb: 1, flexDirection: "column" } }, onTabChanged: function (index) { return setEmbedSource(index === 0 ? "url" : "code"); } }, { children: [_jsxs(Tab, __assign({ title: "From URL" }, { children: [_jsx(Input, { placeholder: "Enter embed source URL", value: src, autoFocus: true, onChange: function (e) { return setSrc(e.target.value); }, autoCapitalize: "none", sx: { fontSize: "body" } }), _jsxs(Flex, __assign({ sx: { alignItems: "center", mt: 1 } }, { children: [_jsx(InlineInput, { containerProps: { sx: { mr: 1 } }, label: "width", type: "number", placeholder: "Width", value: width, sx: { + } }, { children: ["Error: ", error] }))), _jsxs(Tabs, __assign({ activeIndex: 0, containerProps: { sx: { mx: 2, mb: 1, flexDirection: "column" } }, onTabChanged: function (index) { return setEmbedSource(index === 0 ? "url" : "code"); } }, { children: [_jsxs(Tab, __assign({ title: "From URL" }, { children: [_jsx(Input, { placeholder: "Enter embed source URL", value: src, autoFocus: true, onChange: function (e) { return setSrc(e.target.value); }, autoCapitalize: "none", sx: { fontSize: "body" } }), _jsxs(Flex, __assign({ sx: { alignItems: "center", mt: 1 } }, { children: [_jsx(InlineInput, { containerProps: { sx: { mr: 1 } }, label: "width", type: "number", placeholder: "Width", value: width, sx: { mr: 1, fontSize: "body", }, onChange: function (e) { return onSizeChange(e.target.valueAsNumber); } }), _jsx(InlineInput, { label: "height", type: "number", placeholder: "Height", value: height, sx: { fontSize: "body" }, onChange: function (e) { return onSizeChange(undefined, e.target.valueAsNumber); - } })] }))] })), _jsx(Tab, __assign({ title: "From code" }, { children: _jsx(Textarea, { autoFocus: true, variant: "forms.input", sx: { fontSize: "subBody", fontFamily: "monospace" }, minHeight: [200, 100], onChange: function (e) { return setSrc(e.target.value); }, placeholder: "Paste embed code here. Only iframes are supported." }) }))] })), _jsx(Button, __assign({ variant: "primary", sx: { - alignSelf: ["stretch", "end", "end"], - my: 1, - mr: 1, - ml: [1, 0], - py: 2, - }, onClick: function () { - setError(null); - var _src = src; - var _width = width; - var _height = height; - if (embedSource === "code") { - var document_1 = new DOMParser().parseFromString(src, "text/html"); - if (document_1.getElementsByTagName("iframe").length <= 0) - return setError("Embed code must include an iframe."); - var srcValue = getAttribute(document_1, "src"); - if (!srcValue) - return setError("Embed code must include an iframe with an src attribute."); - _src = srcValue; - var widthValue = getAttribute(document_1, "width"); - if (widthValue && !isNaN(parseInt(widthValue))) - _width = parseInt(widthValue); - var heightValue = getAttribute(document_1, "height"); - if (heightValue && !isNaN(parseInt(heightValue))) - _height = parseInt(heightValue); - } - var convertedUrl = convertUrlToEmbedUrl(_src); - if (!!convertedUrl) - _src = convertedUrl; - onClose({ - height: _height, - width: _width, - src: _src, - }); - } }, { children: title }))] })) }))); + } })] }))] })), _jsx(Tab, __assign({ title: "From code" }, { children: _jsx(Textarea, { autoFocus: true, variant: "forms.input", sx: { fontSize: "subBody", fontFamily: "monospace" }, minHeight: [200, 100], onChange: function (e) { return setSrc(e.target.value); }, placeholder: "Paste embed code here. Only iframes are supported." }) }))] }))] })) }))); } function getAttribute(document, id) { var element = document.querySelector("[".concat(id, "]")); diff --git a/packages/editor/dist/toolbar/popups/imageupload.js b/packages/editor/dist/toolbar/popups/imageupload.js index 17144cf3c..bfc42a4ff 100644 --- a/packages/editor/dist/toolbar/popups/imageupload.js +++ b/packages/editor/dist/toolbar/popups/imageupload.js @@ -64,46 +64,74 @@ var __read = (this && this.__read) || function (o, n) { import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Input } from "@rebass/forms"; import { useState } from "react"; -import { Flex } from "rebass"; -import { Button } from "../../components/button"; +import { Flex, Text } from "rebass"; import { Popup } from "../components/popup"; export function ImageUploadPopup(props) { var _this = this; var onInsert = props.onInsert, onClose = props.onClose; - var _a = __read(useState(""), 2), url = _a[0], setUrl = _a[1]; - return (_jsx(Popup, __assign({ title: "Upload image from URL", onClose: onClose }, { children: _jsxs(Flex, __assign({ sx: { p: 1, flexDirection: "column", width: ["auto", 250] } }, { children: [_jsx(Input, { type: "url", sx: { - height: "45px", - }, autoFocus: true, placeholder: "Paste Image URL here", value: url, onChange: function (e) { return setUrl(e.target.value); } }), _jsx(Button, __assign({ variant: "primary", sx: { - alignSelf: ["stretch", "end", "end"], - my: 1, - mr: [0, 1], - }, onClick: function () { return __awaiter(_this, void 0, void 0, function () { - var response, contentType, contentLength, size, dataurl, _a; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: return [4 /*yield*/, fetch(url)]; - case 1: - response = _b.sent(); - if (!response.ok) - return [2 /*return*/]; // TODO show error - contentType = response.headers.get("Content-Type"); - contentLength = response.headers.get("Content-Length"); - if (!contentType || - !contentLength || - contentLength === "0" || - !contentType.startsWith("image/")) - return [2 /*return*/]; - size = parseInt(contentLength); - _a = toDataURL; - return [4 /*yield*/, response.blob()]; - case 2: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])]; - case 3: - dataurl = _b.sent(); - onInsert({ src: dataurl, type: contentType, size: size }); - return [2 /*return*/]; - } - }); - }); }, disabled: !url.trim() }, { children: "Insert image" }))] })) }))); + var _a = __read(useState(false), 2), isDownloading = _a[0], setIsDownloading = _a[1]; + var _b = __read(useState(), 2), error = _b[0], setError = _b[1]; + var _c = __read(useState(""), 2), url = _c[0], setUrl = _c[1]; + return (_jsx(Popup, __assign({ title: "Insert image from URL", onClose: onClose, action: { + loading: isDownloading, + title: "Insert image", + onClick: function () { return __awaiter(_this, void 0, void 0, function () { + var response, contentType, contentLength, size, dataurl, _a, e_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + setIsDownloading(true); + setError(undefined); + _b.label = 1; + case 1: + _b.trys.push([1, 5, 6, 7]); + return [4 /*yield*/, fetch(url)]; + case 2: + response = _b.sent(); + if (!response.ok) + return [2 /*return*/, setError("invalid status code ".concat(response.status))]; + contentType = response.headers.get("Content-Type"); + contentLength = response.headers.get("Content-Length"); + if (!contentType || + !contentLength || + contentLength === "0" || + !contentType.startsWith("image/")) + return [2 /*return*/, setError("not an image")]; + size = parseInt(contentLength); + _a = toDataURL; + return [4 /*yield*/, response.blob()]; + case 3: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])]; + case 4: + dataurl = _b.sent(); + onInsert({ src: dataurl, type: contentType, size: size }); + return [3 /*break*/, 7]; + case 5: + e_1 = _b.sent(); + if (e_1 instanceof Error) + setError(e_1.message); + return [3 /*break*/, 7]; + case 6: + setIsDownloading(false); + return [7 /*endfinally*/]; + case 7: return [2 /*return*/]; + } + }); + }); }, + } }, { children: _jsxs(Flex, __assign({ sx: { px: 2, flexDirection: "column", width: ["auto", 350] } }, { children: [_jsx(Input, { type: "url", autoFocus: true, placeholder: "Paste Image URL here", value: url, onChange: function (e) { + setUrl(e.target.value); + setError(undefined); + } }), error ? (_jsxs(Text, __assign({ variant: "error", sx: { + bg: "errorBg", + mt: 1, + p: 1, + borderRadius: "default", + } }, { children: ["Failed to download image: ", error.toLowerCase(), "."] }))) : (_jsx(Text, __assign({ variant: "subBody", sx: { + bg: "shade", + color: "primary", + mt: 1, + p: 1, + borderRadius: "default", + } }, { children: "To protect your privacy, we will download the image & add it to your attachments." })))] })) }))); } function toDataURL(blob) { return new Promise(function (resolve, reject) { diff --git a/packages/editor/dist/toolbar/tooldefinitions.js b/packages/editor/dist/toolbar/tooldefinitions.js index 2367c6561..578eb4998 100644 --- a/packages/editor/dist/toolbar/tooldefinitions.js +++ b/packages/editor/dist/toolbar/tooldefinitions.js @@ -152,7 +152,7 @@ var tools = { conditional: true, }, moveColumnRight: { - icon: "moveColumnLeft", + icon: "moveColumnRight", title: "Move column right", conditional: true, }, diff --git a/packages/editor/dist/toolbar/tools/block.js b/packages/editor/dist/toolbar/tools/block.js index 51e4f28a0..202ac1b2b 100644 --- a/packages/editor/dist/toolbar/tools/block.js +++ b/packages/editor/dist/toolbar/tools/block.js @@ -127,12 +127,12 @@ var table = function (editor) { return ({ key: "table-size-selector", type: "popup", component: function (props) { return (_jsx(TablePopup, { onInsertTable: function (size) { - var _a; - editor === null || editor === void 0 ? void 0 : editor.chain().focus().insertTable({ + var _a, _b; + (_a = editor.current) === null || _a === void 0 ? void 0 : _a.chain().focus().insertTable({ rows: size.rows, cols: size.columns, }).run(); - (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props); + (_b = props.onClick) === null || _b === void 0 ? void 0 : _b.call(props); } })); }, }, ], diff --git a/packages/editor/package-lock.json b/packages/editor/package-lock.json index cd20c2f32..86eb7ae87 100644 --- a/packages/editor/package-lock.json +++ b/packages/editor/package-lock.json @@ -13,7 +13,7 @@ "@notesnook/theme": "github:streetwriters/themeprovider", "@rebass/forms": "^4.0.6", "@social-embed/lib": "^0.0.1-next.12", - "@tiptap/core": "^2.0.0-beta.176", + "@tiptap/core": "^2.0.0-beta.180", "@tiptap/extension-character-count": "^2.0.0-beta.26", "@tiptap/extension-color": "^2.0.0-beta.9", "@tiptap/extension-font-family": "^2.0.0-beta.21", @@ -3825,24 +3825,17 @@ } }, "node_modules/@tiptap/core": { - "version": "2.0.0-beta.176", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.176.tgz", - "integrity": "sha512-Gs/+yUYTNpt8PnclEHbfBnY56D/9PpKTyzrg8VZwCFK9S69aVD2dqLsYs/Gn+EjzKImXRAiqSe1/FWcNEDkmCg==", + "version": "2.0.0-beta.180", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.180.tgz", + "integrity": "sha512-aMMMy95k7r+JkxgqhWQwLLmLQUeI60AR3OfpFvK6JdLrZjkx/g7ugPAH6gJNcI6q0z30rTnOL13+iMcnBLyHcQ==", "dependencies": { - "@types/prosemirror-commands": "^1.0.4", - "@types/prosemirror-keymap": "^1.0.4", - "@types/prosemirror-model": "^1.16.0", - "@types/prosemirror-schema-list": "^1.0.3", - "@types/prosemirror-state": "^1.2.8", - "@types/prosemirror-transform": "^1.1.5", - "@types/prosemirror-view": "^1.23.1", - "prosemirror-commands": "^1.2.1", - "prosemirror-keymap": "^1.1.5", - "prosemirror-model": "^1.16.1", - "prosemirror-schema-list": "^1.1.6", - "prosemirror-state": "^1.3.4", - "prosemirror-transform": "^1.3.3", - "prosemirror-view": "^1.23.6" + "prosemirror-commands": "^1.3.0", + "prosemirror-keymap": "^1.2.0", + "prosemirror-model": "^1.17.0", + "prosemirror-schema-list": "^1.2.0", + "prosemirror-state": "^1.4.0", + "prosemirror-transform": "^1.6.0", + "prosemirror-view": "^1.25.0" }, "funding": { "type": "github", @@ -4615,16 +4608,6 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, - "node_modules/@types/prosemirror-commands": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz", - "integrity": "sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==", - "dependencies": { - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-view": "*" - } - }, "node_modules/@types/prosemirror-dropcursor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz", @@ -4651,17 +4634,6 @@ "@types/prosemirror-state": "*" } }, - "node_modules/@types/prosemirror-keymap": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz", - "integrity": "sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==", - "dependencies": { - "@types/prosemirror-commands": "*", - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-view": "*" - } - }, "node_modules/@types/prosemirror-model": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.16.2.tgz", @@ -4670,16 +4642,6 @@ "@types/orderedmap": "*" } }, - "node_modules/@types/prosemirror-schema-list": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz", - "integrity": "sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==", - "dependencies": { - "@types/orderedmap": "*", - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*" - } - }, "node_modules/@types/prosemirror-state": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.3.0.tgz", @@ -18837,9 +18799,9 @@ } }, "node_modules/prosemirror-transform": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.5.0.tgz", - "integrity": "sha512-uYbTiuY7KMeBG2WprTD1Qz7ge4enD0ZD84Vg7rHqHT6U9LmyKLSETovWNSdikq+LVYOejc+7P8/a1pdmiWV4Pw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.6.0.tgz", + "integrity": "sha512-MAp7AjsjEGEqQY0sSMufNIUuEyB1ZR9Fqlm8dTwwWwpEJRv/plsKjWXBbx52q3Ml8MtaMcd7ic14zAHVB3WaMw==", "dependencies": { "prosemirror-model": "^1.0.0" } @@ -18854,9 +18816,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.24.1.tgz", - "integrity": "sha512-7XYxzdeN2s/y3lSs0vmU57r/fIqC/Ee61qGhdo9kN0vf6k83ISE0ioGx9fjtbNaiyiZ8dntJm2l1RGxixvqwqg==", + "version": "1.26.2", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.2.tgz", + "integrity": "sha512-CGKw+GadkfSBEwRAJTHCEKJ4DlV6/3IhAdjpwGyZHUHtbP7jX4Ol4zmi7xa2c6GOabDlIJLYXJydoNYLX7lNeQ==", "dependencies": { "prosemirror-model": "^1.16.0", "prosemirror-state": "^1.0.0", @@ -28341,24 +28303,17 @@ } }, "@tiptap/core": { - "version": "2.0.0-beta.176", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.176.tgz", - "integrity": "sha512-Gs/+yUYTNpt8PnclEHbfBnY56D/9PpKTyzrg8VZwCFK9S69aVD2dqLsYs/Gn+EjzKImXRAiqSe1/FWcNEDkmCg==", + "version": "2.0.0-beta.180", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.180.tgz", + "integrity": "sha512-aMMMy95k7r+JkxgqhWQwLLmLQUeI60AR3OfpFvK6JdLrZjkx/g7ugPAH6gJNcI6q0z30rTnOL13+iMcnBLyHcQ==", "requires": { - "@types/prosemirror-commands": "^1.0.4", - "@types/prosemirror-keymap": "^1.0.4", - "@types/prosemirror-model": "^1.16.0", - "@types/prosemirror-schema-list": "^1.0.3", - "@types/prosemirror-state": "^1.2.8", - "@types/prosemirror-transform": "^1.1.5", - "@types/prosemirror-view": "^1.23.1", - "prosemirror-commands": "^1.2.1", - "prosemirror-keymap": "^1.1.5", - "prosemirror-model": "^1.16.1", - "prosemirror-schema-list": "^1.1.6", - "prosemirror-state": "^1.3.4", - "prosemirror-transform": "^1.3.3", - "prosemirror-view": "^1.23.6" + "prosemirror-commands": "^1.3.0", + "prosemirror-keymap": "^1.2.0", + "prosemirror-model": "^1.17.0", + "prosemirror-schema-list": "^1.2.0", + "prosemirror-state": "^1.4.0", + "prosemirror-transform": "^1.6.0", + "prosemirror-view": "^1.25.0" } }, "@tiptap/extension-blockquote": { @@ -28876,16 +28831,6 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, - "@types/prosemirror-commands": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz", - "integrity": "sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==", - "requires": { - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-view": "*" - } - }, "@types/prosemirror-dropcursor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz", @@ -28912,17 +28857,6 @@ "@types/prosemirror-state": "*" } }, - "@types/prosemirror-keymap": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz", - "integrity": "sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==", - "requires": { - "@types/prosemirror-commands": "*", - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*", - "@types/prosemirror-view": "*" - } - }, "@types/prosemirror-model": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.16.2.tgz", @@ -28931,16 +28865,6 @@ "@types/orderedmap": "*" } }, - "@types/prosemirror-schema-list": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz", - "integrity": "sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==", - "requires": { - "@types/orderedmap": "*", - "@types/prosemirror-model": "*", - "@types/prosemirror-state": "*" - } - }, "@types/prosemirror-state": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.3.0.tgz", @@ -40130,9 +40054,9 @@ } }, "prosemirror-transform": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.5.0.tgz", - "integrity": "sha512-uYbTiuY7KMeBG2WprTD1Qz7ge4enD0ZD84Vg7rHqHT6U9LmyKLSETovWNSdikq+LVYOejc+7P8/a1pdmiWV4Pw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.6.0.tgz", + "integrity": "sha512-MAp7AjsjEGEqQY0sSMufNIUuEyB1ZR9Fqlm8dTwwWwpEJRv/plsKjWXBbx52q3Ml8MtaMcd7ic14zAHVB3WaMw==", "requires": { "prosemirror-model": "^1.0.0" } @@ -40143,9 +40067,9 @@ "requires": {} }, "prosemirror-view": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.24.1.tgz", - "integrity": "sha512-7XYxzdeN2s/y3lSs0vmU57r/fIqC/Ee61qGhdo9kN0vf6k83ISE0ioGx9fjtbNaiyiZ8dntJm2l1RGxixvqwqg==", + "version": "1.26.2", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.2.tgz", + "integrity": "sha512-CGKw+GadkfSBEwRAJTHCEKJ4DlV6/3IhAdjpwGyZHUHtbP7jX4Ol4zmi7xa2c6GOabDlIJLYXJydoNYLX7lNeQ==", "requires": { "prosemirror-model": "^1.16.0", "prosemirror-state": "^1.0.0", diff --git a/packages/editor/package.json b/packages/editor/package.json index fad4ce9d7..6ad9d299f 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -9,7 +9,7 @@ "@notesnook/theme": "github:streetwriters/themeprovider", "@rebass/forms": "^4.0.6", "@social-embed/lib": "^0.0.1-next.12", - "@tiptap/core": "^2.0.0-beta.176", + "@tiptap/core": "^2.0.0-beta.180", "@tiptap/extension-character-count": "^2.0.0-beta.26", "@tiptap/extension-color": "^2.0.0-beta.9", "@tiptap/extension-font-family": "^2.0.0-beta.21", diff --git a/packages/editor/src/components/popup-presenter/index.tsx b/packages/editor/src/components/popup-presenter/index.tsx index 54e38179c..5475e269a 100644 --- a/packages/editor/src/components/popup-presenter/index.tsx +++ b/packages/editor/src/components/popup-presenter/index.tsx @@ -54,7 +54,6 @@ function _PopupPresenter(props: PropsWithChildren) { const popupPosition = getPosition(popup, position); popup.style.top = popupPosition.top + "px"; popup.style.left = popupPosition.left + "px"; - console.log("popup", popupPosition); }, [position]); useEffect(() => { diff --git a/packages/editor/src/extensions/table/actions.ts b/packages/editor/src/extensions/table/actions.ts index a7bb55e7b..00cad2c5a 100644 --- a/packages/editor/src/extensions/table/actions.ts +++ b/packages/editor/src/extensions/table/actions.ts @@ -71,7 +71,6 @@ function getColumnCells({ map, table }: TableRect, col: number) { cells.push({ cell, pos }); row += cell.attrs.rowspan; - console.log(cell.textContent); } return cells; diff --git a/packages/editor/src/extensions/table/component.tsx b/packages/editor/src/extensions/table/component.tsx index 7eacddb08..624408a4a 100644 --- a/packages/editor/src/extensions/table/component.tsx +++ b/packages/editor/src/extensions/table/component.tsx @@ -1,27 +1,13 @@ -import { Flex, Text } from "rebass"; +import { Flex } from "rebass"; import { - createNodeView, - ReactNodeView, - ReactNodeViewProps, SelectionBasedNodeView, SelectionBasedReactNodeViewProps, } from "../react"; -import { Icon } from "../../toolbar/components/icon"; -import { Icons } from "../../toolbar/icons"; import { Node as ProsemirrorNode } from "prosemirror-model"; -import { Transaction } from "prosemirror-state"; -import { - Editor, - findChildren, - findParentNode, - getNodeType, - NodeWithPos, -} from "@tiptap/core"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { Editor } from "@tiptap/core"; +import { useEffect, useRef } from "react"; import { updateColumnsOnResize } from "prosemirror-tables"; -import { Decoration, DecorationSource, NodeView } from "prosemirror-view"; -import { TableOptions } from "./table"; -import { ToolbarGroup } from "../../toolbar/components/toolbar-group"; +import { NodeView } from "prosemirror-view"; import { InsertColumnRight, InsertRowBelow, @@ -29,7 +15,7 @@ import { TableProperties, } from "../../toolbar/tools/table"; import { getToolDefinition } from "../../toolbar/tool-definitions"; -import { getPosition, PositionOptions } from "../../utils/position"; +import { getPosition } from "../../utils/position"; import { findSelectedDOMNode } from "../../toolbar/utils/prosemirror"; import { DesktopOnly } from "../../components/responsive"; diff --git a/packages/editor/src/extensions/table/table.ts b/packages/editor/src/extensions/table/table.ts index 7dca45f10..a04aa22ac 100644 --- a/packages/editor/src/extensions/table/table.ts +++ b/packages/editor/src/extensions/table/table.ts @@ -1,280 +1,8 @@ -import { - callOrReturn, - getExtensionField, - mergeAttributes, - Node, - ParentConfig, -} from "@tiptap/core"; -import { TextSelection } from "prosemirror-state"; -import { - addColumnAfter, - addColumnBefore, - addRowAfter, - addRowBefore, - CellSelection, - columnResizing, - deleteColumn, - deleteRow, - deleteTable, - fixTables, - goToNextCell, - mergeCells, - setCellAttr, - splitCell, - tableEditing, - toggleHeader, - toggleHeaderCell, -} from "prosemirror-tables"; -import { NodeView } from "prosemirror-view"; - +import { Table as TiptapTable, TableOptions } from "@tiptap/extension-table"; +import { columnResizing, tableEditing } from "prosemirror-tables"; import { TableNodeView } from "./component"; -import { createTable } from "./utils/createTable"; -import { deleteTableWhenAllCellsSelected } from "./utils/deleteTableWhenAllCellsSelected"; - -export interface TableOptions { - HTMLAttributes: Record; - resizable: boolean; - handleWidth: number; - cellMinWidth: number; - View: NodeView; - lastColumnResizable: boolean; - allowTableNodeSelection: boolean; -} - -declare module "@tiptap/core" { - interface Commands { - table: { - insertTable: (options?: { - rows?: number; - cols?: number; - withHeaderRow?: boolean; - }) => ReturnType; - addColumnBefore: () => ReturnType; - addColumnAfter: () => ReturnType; - deleteColumn: () => ReturnType; - addRowBefore: () => ReturnType; - addRowAfter: () => ReturnType; - deleteRow: () => ReturnType; - deleteTable: () => ReturnType; - mergeCells: () => ReturnType; - splitCell: () => ReturnType; - toggleHeaderColumn: () => ReturnType; - toggleHeaderRow: () => ReturnType; - toggleHeaderCell: () => ReturnType; - mergeOrSplit: () => ReturnType; - setCellAttribute: (name: string, value: any) => ReturnType; - goToNextCell: () => ReturnType; - goToPreviousCell: () => ReturnType; - fixTables: () => ReturnType; - setCellSelection: (position: { - anchorCell: number; - headCell?: number; - }) => ReturnType; - }; - } - - interface NodeConfig { - /** - * Table Role - */ - tableRole?: - | string - | ((this: { - name: string; - options: Options; - storage: Storage; - parent: ParentConfig>["tableRole"]; - }) => string); - } -} - -export const Table = Node.create({ - name: "table", - - // @ts-ignore - addOptions() { - return { - HTMLAttributes: {}, - resizable: false, - handleWidth: 5, - cellMinWidth: 25, - // TODO: fix - View: null, - lastColumnResizable: true, - allowTableNodeSelection: false, - }; - }, - - content: "tableRow+", - - tableRole: "table", - - isolating: true, - - group: "block", - - parseHTML() { - return [{ tag: "table" }]; - }, - - renderHTML({ HTMLAttributes }) { - return [ - "table", - mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), - ["tbody", 0], - ]; - }, - - addCommands() { - return { - insertTable: - ({ rows = 3, cols = 3, withHeaderRow = true } = {}) => - ({ tr, dispatch, editor }) => { - const node = createTable(editor.schema, rows, cols, withHeaderRow); - - if (dispatch) { - const offset = tr.selection.anchor + 1; - - tr.replaceSelectionWith(node) - .scrollIntoView() - .setSelection(TextSelection.near(tr.doc.resolve(offset))); - } - - return true; - }, - addColumnBefore: - () => - ({ state, dispatch }) => { - return addColumnBefore(state, dispatch); - }, - addColumnAfter: - () => - ({ state, dispatch }) => { - return addColumnAfter(state, dispatch); - }, - deleteColumn: - () => - ({ state, dispatch }) => { - return deleteColumn(state, dispatch); - }, - addRowBefore: - () => - ({ state, dispatch }) => { - return addRowBefore(state, dispatch); - }, - addRowAfter: - () => - ({ state, dispatch }) => { - return addRowAfter(state, dispatch); - }, - deleteRow: - () => - ({ state, dispatch }) => { - return deleteRow(state, dispatch); - }, - deleteTable: - () => - ({ state, dispatch }) => { - return deleteTable(state, dispatch); - }, - mergeCells: - () => - ({ state, dispatch }) => { - return mergeCells(state, dispatch); - }, - splitCell: - () => - ({ state, dispatch }) => { - return splitCell(state, dispatch); - }, - toggleHeaderColumn: - () => - ({ state, dispatch }) => { - return toggleHeader("column")(state, dispatch); - }, - toggleHeaderRow: - () => - ({ state, dispatch }) => { - return toggleHeader("row")(state, dispatch); - }, - toggleHeaderCell: - () => - ({ state, dispatch }) => { - return toggleHeaderCell(state, dispatch); - }, - mergeOrSplit: - () => - ({ state, dispatch }) => { - if (mergeCells(state, dispatch)) { - return true; - } - - return splitCell(state, dispatch); - }, - setCellAttribute: - (name, value) => - ({ state, dispatch }) => { - return setCellAttr(name, value)(state, dispatch); - }, - goToNextCell: - () => - ({ state, dispatch }) => { - return goToNextCell(1)(state, dispatch); - }, - goToPreviousCell: - () => - ({ state, dispatch }) => { - return goToNextCell(-1)(state, dispatch); - }, - fixTables: - () => - ({ state, dispatch }) => { - if (dispatch) { - fixTables(state); - } - - return true; - }, - setCellSelection: - (position) => - ({ tr, dispatch }) => { - if (dispatch) { - const selection = CellSelection.create( - tr.doc, - position.anchorCell, - position.headCell - ); - - // @ts-ignore - tr.setSelection(selection); - } - - return true; - }, - }; - }, - - addKeyboardShortcuts() { - return { - Tab: () => { - if (this.editor.commands.goToNextCell()) { - return true; - } - - if (!this.editor.can().addRowAfter()) { - return false; - } - - return this.editor.chain().addRowAfter().goToNextCell().run(); - }, - "Shift-Tab": () => this.editor.commands.goToPreviousCell(), - Backspace: deleteTableWhenAllCellsSelected, - "Mod-Backspace": deleteTableWhenAllCellsSelected, - Delete: deleteTableWhenAllCellsSelected, - "Mod-Delete": deleteTableWhenAllCellsSelected, - }; - }, +export const Table = TiptapTable.extend({ addProseMirrorPlugins() { const isResizable = this.options.resizable && this.editor.isEditable; @@ -296,18 +24,4 @@ export const Table = Node.create({ }), ]; }, - - extendNodeSchema(extension) { - const context = { - name: extension.name, - options: extension.options, - storage: extension.storage, - }; - - return { - tableRole: callOrReturn( - getExtensionField(extension, "tableRole", context) - ), - }; - }, }); diff --git a/packages/editor/src/extensions/table/utils/createCell.ts b/packages/editor/src/extensions/table/utils/createCell.ts deleted file mode 100644 index 0d4c29c2f..000000000 --- a/packages/editor/src/extensions/table/utils/createCell.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { - Fragment, - Node as ProsemirrorNode, - NodeType, - Schema, -} from "prosemirror-model"; - -export function createCell( - cellType: NodeType, - cellContent?: Fragment | ProsemirrorNode | Array -): ProsemirrorNode | null | undefined { - if (cellContent) { - return cellType.createChecked(null, cellContent); - } - - return cellType.createAndFill(); -} diff --git a/packages/editor/src/extensions/table/utils/createTable.ts b/packages/editor/src/extensions/table/utils/createTable.ts deleted file mode 100644 index d970c3166..000000000 --- a/packages/editor/src/extensions/table/utils/createTable.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Fragment, Node as ProsemirrorNode, Schema } from "prosemirror-model"; - -import { createCell } from "./createCell"; -import { getTableNodeTypes } from "./getTableNodeTypes"; - -export function createTable( - schema: Schema, - rowsCount: number, - colsCount: number, - withHeaderRow: boolean, - cellContent?: Fragment | ProsemirrorNode | Array -): ProsemirrorNode { - const types = getTableNodeTypes(schema); - const headerCells = []; - const cells = []; - - for (let index = 0; index < colsCount; index += 1) { - const cell = createCell(types.cell, cellContent); - - if (cell) { - cells.push(cell); - } - - if (withHeaderRow) { - const headerCell = createCell(types.header_cell, cellContent); - - if (headerCell) { - headerCells.push(headerCell); - } - } - } - - const rows = []; - - for (let index = 0; index < rowsCount; index += 1) { - rows.push( - types.row.createChecked( - null, - withHeaderRow && index === 0 ? headerCells : cells - ) - ); - } - - return types.table.createChecked(null, rows); -} diff --git a/packages/editor/src/extensions/table/utils/deleteTableWhenAllCellsSelected.ts b/packages/editor/src/extensions/table/utils/deleteTableWhenAllCellsSelected.ts deleted file mode 100644 index 50ebaeee8..000000000 --- a/packages/editor/src/extensions/table/utils/deleteTableWhenAllCellsSelected.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { findParentNodeClosestToPos, KeyboardShortcutCommand } from '@tiptap/core' - -import { isCellSelection } from './isCellSelection' - -export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => { - const { selection } = editor.state - - if (!isCellSelection(selection)) { - return false - } - - let cellCount = 0 - const table = findParentNodeClosestToPos(selection.ranges[0].$from, node => { - return node.type.name === 'table' - }) - - table?.node.descendants(node => { - if (node.type.name === 'table') { - return false - } - - if (['tableCell', 'tableHeader'].includes(node.type.name)) { - cellCount += 1 - } - }) - - const allCellsSelected = cellCount === selection.ranges.length - - if (!allCellsSelected) { - return false - } - - editor.commands.deleteTable() - - return true -} diff --git a/packages/editor/src/extensions/table/utils/getTableNodeTypes.ts b/packages/editor/src/extensions/table/utils/getTableNodeTypes.ts deleted file mode 100644 index 489e201cf..000000000 --- a/packages/editor/src/extensions/table/utils/getTableNodeTypes.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { NodeType, Schema } from 'prosemirror-model' - -export function getTableNodeTypes(schema: Schema): { [key: string]: NodeType } { - if (schema.cached.tableNodeTypes) { - return schema.cached.tableNodeTypes - } - - const roles: { [key: string]: NodeType } = {} - - Object.keys(schema.nodes).forEach(type => { - const nodeType = schema.nodes[type] - - if (nodeType.spec.tableRole) { - roles[nodeType.spec.tableRole] = nodeType - } - }) - - schema.cached.tableNodeTypes = roles - - return roles -} diff --git a/packages/editor/src/extensions/table/utils/isCellSelection.ts b/packages/editor/src/extensions/table/utils/isCellSelection.ts deleted file mode 100644 index 4fc826e6c..000000000 --- a/packages/editor/src/extensions/table/utils/isCellSelection.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { CellSelection } from 'prosemirror-tables' - -export function isCellSelection(value: unknown): value is CellSelection { - return value instanceof CellSelection -} diff --git a/packages/editor/src/toolbar/components/popup.tsx b/packages/editor/src/toolbar/components/popup.tsx index 094492f2a..2f90c8881 100644 --- a/packages/editor/src/toolbar/components/popup.tsx +++ b/packages/editor/src/toolbar/components/popup.tsx @@ -5,13 +5,19 @@ import { PropsWithChildren } from "react"; import { SchemeColors } from "@notesnook/theme/dist/theme/colorscheme"; import { DesktopOnly, MobileOnly } from "../../components/responsive"; +type Action = { + title: string; + onClick: () => void; + loading?: boolean; +}; export type PopupProps = { title?: string; onClose: () => void; + action?: Action; }; export function Popup(props: PropsWithChildren) { - const { title, onClose, children } = props; + const { title, onClose, action, children } = props; return ( <> @@ -30,23 +36,42 @@ export function Popup(props: PropsWithChildren) { - {title} + {title} {children} + {action && ( + + + + )} {children} diff --git a/packages/editor/src/toolbar/components/tool-button.tsx b/packages/editor/src/toolbar/components/tool-button.tsx index dd5a9d053..a4575955b 100644 --- a/packages/editor/src/toolbar/components/tool-button.tsx +++ b/packages/editor/src/toolbar/components/tool-button.tsx @@ -29,7 +29,6 @@ export const ToolButton = React.memo( variant = "normal", ...buttonProps } = props; - console.log("rerendering", props.title); return ( + */} ); diff --git a/packages/editor/src/toolbar/popups/image-upload.tsx b/packages/editor/src/toolbar/popups/image-upload.tsx index 7ba828498..b2e86b48a 100644 --- a/packages/editor/src/toolbar/popups/image-upload.tsx +++ b/packages/editor/src/toolbar/popups/image-upload.tsx @@ -1,6 +1,6 @@ import { Input } from "@rebass/forms"; import { useState } from "react"; -import { Flex } from "rebass"; +import { Flex, Text } from "rebass"; import { ImageAttributes } from "../../extensions/image"; import { Button } from "../../components/button"; import { Popup } from "../components/popup"; @@ -11,31 +11,25 @@ export type ImageUploadPopupProps = { }; export function ImageUploadPopup(props: ImageUploadPopupProps) { const { onInsert, onClose } = props; + const [isDownloading, setIsDownloading] = useState(false); + const [error, setError] = useState(); const [url, setUrl] = useState(""); return ( - - - setUrl(e.target.value)} - /> - + /> + + {error ? ( + + Failed to download image: {error.toLowerCase()}. + + ) : ( + + To protect your privacy, we will download the image & add it to + your attachments. + + )} ); @@ -70,3 +106,17 @@ function toDataURL(blob: Blob): Promise { reader.readAsDataURL(blob); }); } + +// async function validateURL(url: string): Promise { +// try { +// const response = await fetch(url, { method: "HEAD" }); + +// return ( +// response.ok && +// !!response.headers.get("Content-Type")?.startsWith("image/") && +// response.headers.get("Content-Length") !== "0" +// ); +// } catch { +// return false; +// } +// } diff --git a/packages/editor/src/toolbar/tool-definitions.ts b/packages/editor/src/toolbar/tool-definitions.ts index 25971db12..5296aafe8 100644 --- a/packages/editor/src/toolbar/tool-definitions.ts +++ b/packages/editor/src/toolbar/tool-definitions.ts @@ -156,7 +156,7 @@ const tools: Record = { conditional: true, }, moveColumnRight: { - icon: "moveColumnLeft", + icon: "moveColumnRight", title: "Move column right", conditional: true, }, diff --git a/packages/editor/src/toolbar/tools/block.tsx b/packages/editor/src/toolbar/tools/block.tsx index 90bffc187..c7862b041 100644 --- a/packages/editor/src/toolbar/tools/block.tsx +++ b/packages/editor/src/toolbar/tools/block.tsx @@ -134,7 +134,7 @@ const table = (editor: Editor): MenuItem => ({ component: (props) => ( { - editor + editor.current ?.chain() .focus() .insertTable({