mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 11:47:54 +01:00
updates
This commit is contained in:
1
packages/editor/dist/components/menu/index.d.ts
vendored
Normal file
1
packages/editor/dist/components/menu/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { MenuPresenter } from "./menu";
|
||||
1
packages/editor/dist/components/menu/index.js
vendored
Normal file
1
packages/editor/dist/components/menu/index.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { MenuPresenter } from "./menu";
|
||||
21
packages/editor/dist/components/menu/menu.d.ts
vendored
Normal file
21
packages/editor/dist/components/menu/menu.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { PropsWithChildren } from "react";
|
||||
import { FlexProps } from "rebass";
|
||||
import { MenuOptions } from "./useMenu";
|
||||
import { MenuItem as MenuItemType } from "./types";
|
||||
declare type MenuProps = MenuContainerProps & {
|
||||
items: MenuItemType[];
|
||||
closeMenu: () => void;
|
||||
};
|
||||
export declare function Menu(props: MenuProps): JSX.Element;
|
||||
declare type MenuContainerProps = FlexProps & {
|
||||
title?: string;
|
||||
};
|
||||
declare type MenuPresenterProps = MenuContainerProps & {
|
||||
items: MenuItemType[];
|
||||
options: MenuOptions;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
className?: string;
|
||||
};
|
||||
export declare function MenuPresenter(props: PropsWithChildren<MenuPresenterProps>): JSX.Element;
|
||||
export {};
|
||||
234
packages/editor/dist/components/menu/menu.js
vendored
Normal file
234
packages/editor/dist/components/menu/menu.js
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
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 __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useCallback, useRef, useEffect, useState, } from "react";
|
||||
import { Box, Flex, Text } from "rebass";
|
||||
import { getPosition } from "./useMenu";
|
||||
// import { FlexScrollContainer } from "../scrollcontainer";
|
||||
import MenuItem from "./menuitem";
|
||||
// import { useMenuTrigger, useMenu, getPosition } from "../../hooks/useMenu";
|
||||
import Modal from "react-modal";
|
||||
// import { store as selectionStore } from "../../stores/selectionstore";
|
||||
function useMenuFocus(items, onAction, onClose) {
|
||||
var _a = useState(-1), focusIndex = _a[0], setFocusIndex = _a[1];
|
||||
var _b = useState(false), isSubmenuOpen = _b[0], setIsSubmenuOpen = _b[1];
|
||||
var moveItemIntoView = useCallback(function (index) {
|
||||
var item = items[index];
|
||||
if (!item)
|
||||
return;
|
||||
var element = document.getElementById(item.key);
|
||||
if (!element)
|
||||
return;
|
||||
element.scrollIntoView({
|
||||
behavior: "auto",
|
||||
});
|
||||
}, [items]);
|
||||
var onKeyDown = useCallback(function (e) {
|
||||
var isSeperator = function (i) { var _a, _b; return items && (((_a = items[i]) === null || _a === void 0 ? void 0 : _a.type) === "seperator" || ((_b = items[i]) === null || _b === void 0 ? void 0 : _b.isDisabled)); };
|
||||
var moveDown = function (i) { return (i < items.length - 1 ? ++i : 0); };
|
||||
var moveUp = function (i) { return (i > 0 ? --i : items.length - 1); };
|
||||
var hasSubmenu = function (i) { var _a; return items && ((_a = items[i]) === null || _a === void 0 ? void 0 : _a.hasSubmenu); };
|
||||
var openSubmenu = function (index) {
|
||||
if (!hasSubmenu(index))
|
||||
return;
|
||||
setIsSubmenuOpen(true);
|
||||
};
|
||||
var closeSubmenu = function (index) {
|
||||
if (!hasSubmenu(index))
|
||||
return;
|
||||
setIsSubmenuOpen(false);
|
||||
};
|
||||
setFocusIndex(function (i) {
|
||||
var nextIndex = i;
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
if (isSubmenuOpen)
|
||||
break;
|
||||
nextIndex = moveUp(i);
|
||||
while (isSeperator(nextIndex)) {
|
||||
nextIndex = moveUp(nextIndex);
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (isSubmenuOpen)
|
||||
break;
|
||||
nextIndex = moveDown(i);
|
||||
while (isSeperator(nextIndex)) {
|
||||
nextIndex = moveDown(nextIndex);
|
||||
}
|
||||
break;
|
||||
case "ArrowRight":
|
||||
openSubmenu(i);
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
closeSubmenu(i);
|
||||
break;
|
||||
case "Enter":
|
||||
onAction && onAction(e);
|
||||
break;
|
||||
case "Escape":
|
||||
onClose && onClose(e);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (nextIndex !== i)
|
||||
moveItemIntoView(nextIndex);
|
||||
return nextIndex;
|
||||
});
|
||||
}, [items, isSubmenuOpen, moveItemIntoView, onAction]);
|
||||
useEffect(function () {
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return function () {
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
}, [onKeyDown]);
|
||||
return { focusIndex: focusIndex, setFocusIndex: setFocusIndex, isSubmenuOpen: isSubmenuOpen, setIsSubmenuOpen: setIsSubmenuOpen };
|
||||
}
|
||||
export function Menu(props) {
|
||||
var _a;
|
||||
var items = props.items, title = props.title, closeMenu = props.closeMenu, containerProps = __rest(props, ["items", "title", "closeMenu"]);
|
||||
var hoverTimeout = useRef();
|
||||
var onAction = useCallback(function (e, item) {
|
||||
e.stopPropagation();
|
||||
if (closeMenu)
|
||||
closeMenu();
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
}
|
||||
}, [closeMenu]);
|
||||
var _b = useMenuFocus(items, function (e) {
|
||||
var item = items[focusIndex];
|
||||
if (item)
|
||||
onAction(e, item);
|
||||
}, function () { return closeMenu(); }), focusIndex = _b.focusIndex, setFocusIndex = _b.setFocusIndex, isSubmenuOpen = _b.isSubmenuOpen, setIsSubmenuOpen = _b.setIsSubmenuOpen;
|
||||
var subMenuRef = useRef(null);
|
||||
useEffect(function () {
|
||||
var item = items[focusIndex];
|
||||
if (!item || !subMenuRef.current)
|
||||
return;
|
||||
var menuItemElement = document.getElementById(item.key);
|
||||
if (!menuItemElement)
|
||||
return;
|
||||
if (!isSubmenuOpen) {
|
||||
subMenuRef.current.style.visibility = "hidden";
|
||||
return;
|
||||
}
|
||||
var _a = getPosition(subMenuRef.current, {
|
||||
yOffset: menuItemElement.offsetHeight,
|
||||
target: menuItemElement,
|
||||
location: "right",
|
||||
}), top = _a.top, left = _a.left;
|
||||
subMenuRef.current.style.visibility = "visible";
|
||||
subMenuRef.current.style.top = "".concat(top, "px");
|
||||
subMenuRef.current.style.left = "".concat(left, "px");
|
||||
}, [isSubmenuOpen, focusIndex, items]);
|
||||
return (_jsxs(_Fragment, { children: [_jsx(MenuContainer, __assign({}, containerProps, { children: items.map(function (item, index) { return (_jsx(MenuItem, { item: item, onClick: function (e) {
|
||||
var _a;
|
||||
if ((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
setFocusIndex(index);
|
||||
setIsSubmenuOpen(true);
|
||||
}
|
||||
else
|
||||
onAction(e, item);
|
||||
}, isFocused: focusIndex === index, onMouseEnter: function () {
|
||||
var _a;
|
||||
if (item.isDisabled) {
|
||||
setFocusIndex(-1);
|
||||
return;
|
||||
}
|
||||
if (hoverTimeout.current)
|
||||
clearTimeout(hoverTimeout.current);
|
||||
setFocusIndex(index);
|
||||
setIsSubmenuOpen(false);
|
||||
if ((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
hoverTimeout.current = setTimeout(function () {
|
||||
setIsSubmenuOpen(true);
|
||||
}, 500);
|
||||
}
|
||||
}, onMouseLeave: function () {
|
||||
if (hoverTimeout.current)
|
||||
clearTimeout(hoverTimeout.current);
|
||||
} }, item.key)); }) })), isSubmenuOpen && (_jsx(Flex, __assign({ ref: subMenuRef, style: { visibility: "hidden" }, sx: {
|
||||
position: "absolute",
|
||||
} }, { children: _jsx(Menu, { items: ((_a = items[focusIndex]) === null || _a === void 0 ? void 0 : _a.items) || [], closeMenu: closeMenu }) })))] }));
|
||||
}
|
||||
function MenuContainer(props) {
|
||||
var children = props.children, title = props.title, sx = props.sx, flexProps = __rest(props, ["children", "title", "sx"]);
|
||||
return (_jsxs(Box, __assign({ className: "menuContainer", as: "ul", tabIndex: -1, sx: __assign({ bg: "background", py: 1, display: "flex", flexDirection: "column", position: "relative", listStyle: "none", padding: 0, margin: 0, borderRadius: "default", boxShadow: "menu", border: "1px solid var(--border)", width: 220 }, sx) }, flexProps, { children: [title && (_jsx(Text, __assign({ sx: {
|
||||
fontFamily: "body",
|
||||
fontSize: "subtitle",
|
||||
color: "primary",
|
||||
py: "8px",
|
||||
px: 3,
|
||||
borderBottom: "1px solid",
|
||||
borderBottomColor: "border",
|
||||
wordWrap: "break-word",
|
||||
} }, { children: title }))), children] })));
|
||||
}
|
||||
export function MenuPresenter(props) {
|
||||
var className = props.className, options = props.options, items = props.items, isOpen = props.isOpen, onClose = props.onClose, children = props.children, containerProps = __rest(props, ["className", "options", "items", "isOpen", "onClose", "children"]);
|
||||
// const { isOpen, closeMenu } = useMenuTrigger();
|
||||
// const { items, } = useMenu();
|
||||
var position = options.position, type = options.type;
|
||||
var isAutocomplete = type === "autocomplete";
|
||||
var contentRef = useRef();
|
||||
useEffect(function () {
|
||||
if (!contentRef.current || !position)
|
||||
return;
|
||||
var menu = contentRef.current;
|
||||
var menuPosition = getPosition(menu, position);
|
||||
menu.style.top = menuPosition.top + "px";
|
||||
menu.style.left = menuPosition.left + "px";
|
||||
}, [position]);
|
||||
return (_jsx(Modal, __assign({ contentRef: function (ref) { return (contentRef.current = ref); }, className: className || "menuContainer", role: "menu", isOpen: isOpen, appElement: document.body, shouldCloseOnEsc: true, shouldReturnFocusAfterClose: true, shouldCloseOnOverlayClick: true, shouldFocusAfterRender: !isAutocomplete, ariaHideApp: !isAutocomplete, preventScroll: !isAutocomplete, onRequestClose: onClose, portalClassName: className || "menuPresenter", onAfterOpen: function (obj) {
|
||||
if (!obj || !position)
|
||||
return;
|
||||
var menu = obj.contentEl;
|
||||
var menuPosition = getPosition(menu, position);
|
||||
menu.style.top = menuPosition.top + "px";
|
||||
menu.style.left = menuPosition.left + "px";
|
||||
}, overlayElement: function (props, contentEl) {
|
||||
return (_jsx(Box, __assign({}, props, { style: __assign(__assign({}, props.style), { position: isAutocomplete ? "initial" : "fixed", zIndex: 1000, backgroundColor: isAutocomplete ? "transparent" : "unset" }) }, { children: contentEl })));
|
||||
}, contentElement: function (props, children) { return (_jsx(Box, __assign({}, props, { style: {}, sx: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
width: "fit-content",
|
||||
height: "fit-content",
|
||||
position: "absolute",
|
||||
backgroundColor: undefined,
|
||||
padding: 0,
|
||||
zIndex: 0,
|
||||
outline: 0,
|
||||
isolation: "isolate",
|
||||
} }, { children: children }))); }, style: {
|
||||
content: {},
|
||||
overlay: {
|
||||
zIndex: 999,
|
||||
background: "transparent",
|
||||
},
|
||||
} }, { children: props.children ? (props.children) : (_jsx(Menu, __assign({ items: items, closeMenu: onClose }, containerProps))) })));
|
||||
}
|
||||
11
packages/editor/dist/components/menu/menuitem.d.ts
vendored
Normal file
11
packages/editor/dist/components/menu/menuitem.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/// <reference types="react" />
|
||||
import { MenuItem } from "./types";
|
||||
declare type MenuItemProps = {
|
||||
item: MenuItem;
|
||||
isFocused: boolean;
|
||||
onMouseEnter: () => void;
|
||||
onMouseLeave: () => void;
|
||||
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
declare function MenuItem(props: MenuItemProps): JSX.Element;
|
||||
export default MenuItem;
|
||||
49
packages/editor/dist/components/menu/menuitem.js
vendored
Normal file
49
packages/editor/dist/components/menu/menuitem.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
// import { Check, ChevronRight, Pro } from "../icons";
|
||||
import { useRef } from "react";
|
||||
import { Flex, Box, Text, Button } from "rebass";
|
||||
import { Icon } from "../../toolbar/components/icon";
|
||||
import { Icons } from "../../toolbar/icons";
|
||||
function MenuItem(props) {
|
||||
var item = props.item, isFocused = props.isFocused, onMouseEnter = props.onMouseEnter, onMouseLeave = props.onMouseLeave, onClick = props.onClick;
|
||||
var title = item.title, key = item.key,
|
||||
// color,
|
||||
icon = item.icon,
|
||||
// iconColor,
|
||||
type = item.type, tooltip = item.tooltip, isDisabled = item.isDisabled, isChecked = item.isChecked, hasSubmenu = item.hasSubmenu, Component = item.component, modifier = item.modifier;
|
||||
var itemRef = useRef(null);
|
||||
if (type === "seperator")
|
||||
return (_jsx(Box, { as: "li", sx: {
|
||||
width: "95%",
|
||||
height: "0.5px",
|
||||
bg: "border",
|
||||
my: 2,
|
||||
alignSelf: "center",
|
||||
} }, key));
|
||||
return (_jsx(Flex, __assign({ as: "li", sx: { flex: 1, flexDirection: "column" }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave }, { children: _jsx(Button, __assign({ id: key, "data-test-id": "menuitem-".concat(key), ref: itemRef, tabIndex: -1, variant: "menuitem", title: tooltip, disabled: isDisabled, onClick: onClick, sx: {
|
||||
bg: isFocused ? "hover" : "transparent",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
} }, { children: Component ? (_jsx(Component, {})) : (_jsxs(_Fragment, { children: [_jsxs(Flex, { children: [icon && (_jsx(Icon, { path: Icons[icon], color: "text", size: 15, sx: { mr: 2 } })), _jsx(Text, __assign({ as: "span", sx: {
|
||||
fontFamily: "body",
|
||||
fontSize: "menu",
|
||||
color: "text",
|
||||
} }, { children: title }))] }), _jsxs(Flex, { children: [isChecked && _jsx(Icon, { path: Icons.check, size: 14 }), modifier && (_jsx(Text, __assign({ as: "span", sx: {
|
||||
fontFamily: "body",
|
||||
fontSize: "menu",
|
||||
color: "fontTertiary",
|
||||
} }, { children: modifier })))] })] })) }), key) })));
|
||||
}
|
||||
export default MenuItem;
|
||||
17
packages/editor/dist/components/menu/types.d.ts
vendored
Normal file
17
packages/editor/dist/components/menu/types.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/// <reference types="react" />
|
||||
import { IconNames } from "../../toolbar/icons";
|
||||
export declare type MenuItem = {
|
||||
type: "menuitem" | "seperator";
|
||||
key: string;
|
||||
component?: (props: any) => JSX.Element;
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
icon?: IconNames;
|
||||
tooltip?: string;
|
||||
isDisabled?: boolean;
|
||||
isHidden?: boolean;
|
||||
isChecked?: boolean;
|
||||
hasSubmenu?: boolean;
|
||||
modifier?: string;
|
||||
items?: MenuItem[];
|
||||
};
|
||||
20
packages/editor/dist/components/menu/types.js
vendored
Normal file
20
packages/editor/dist/components/menu/types.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// export type ResolverFunction<T, TData> = (
|
||||
// data: any,
|
||||
// item: MenuItem<TData>
|
||||
// ) => T;
|
||||
// export type Resolvable<T, TData> = T | ResolverFunction<T, TData>;
|
||||
// export type MenuItem<TData> = {
|
||||
// type: "menuitem" | "seperator";
|
||||
// key: string;
|
||||
// component?: Resolvable<(props: any) => JSX.Element, TData>;
|
||||
// onClick?: (data: TData, item: MenuItem<TData>) => void;
|
||||
// title?: Resolvable<string, TData>;
|
||||
// icon?: Resolvable<string, TData>;
|
||||
// tooltip?: Resolvable<string, TData>;
|
||||
// disabled?: Resolvable<string, TData>;
|
||||
// hidden?: Resolvable<boolean, TData>;
|
||||
// checked?: Resolvable<boolean, TData>;
|
||||
// modifier?: Resolvable<string[], TData>;
|
||||
// items?: Resolvable<MenuItem<TData>[], TData>;
|
||||
// };
|
||||
export {};
|
||||
28
packages/editor/dist/components/menu/useMenu.d.ts
vendored
Normal file
28
packages/editor/dist/components/menu/useMenu.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
declare type PositionData = {
|
||||
x: number;
|
||||
y: number;
|
||||
actualX: number;
|
||||
actualY: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
};
|
||||
export declare type MenuOptions = {
|
||||
type: "autocomplete" | "menu";
|
||||
position?: PositionOptions;
|
||||
};
|
||||
declare type PositionOptions = {
|
||||
target?: HTMLElement | "mouse";
|
||||
isTargetAbsolute?: boolean;
|
||||
location?: "right" | "left" | "below" | "top";
|
||||
align?: "center" | "start" | "end";
|
||||
yOffset?: number;
|
||||
xOffset?: number;
|
||||
yAnchor?: HTMLElement;
|
||||
parent?: HTMLElement | Element;
|
||||
};
|
||||
export declare function getPosition(element: HTMLElement, options: PositionOptions): {
|
||||
top: number;
|
||||
left: number;
|
||||
};
|
||||
export declare function getElementPosition(element: HTMLElement, absolute: boolean): PositionData;
|
||||
export {};
|
||||
161
packages/editor/dist/components/menu/useMenu.js
vendored
Normal file
161
packages/editor/dist/components/menu/useMenu.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
var mousePosition = { x: 0, y: 0, actualX: 0, actualY: 0 };
|
||||
window.addEventListener("mousemove", function (e) {
|
||||
var _a = getMousePosition(e), x = _a.x, y = _a.y, actualX = _a.actualX, actualY = _a.actualY;
|
||||
mousePosition.x = x;
|
||||
mousePosition.y = y;
|
||||
mousePosition.actualX = actualX;
|
||||
mousePosition.actualY = actualY;
|
||||
});
|
||||
export function getPosition(element, options) {
|
||||
var _a = options || {}, _b = _a.target, target = _b === void 0 ? "mouse" : _b, _c = _a.isTargetAbsolute, isTargetAbsolute = _c === void 0 ? false : _c, _d = _a.location, location = _d === void 0 ? undefined : _d, _e = _a.yOffset, yOffset = _e === void 0 ? 0 : _e, _f = _a.xOffset, xOffset = _f === void 0 ? 0 : _f, _g = _a.align, align = _g === void 0 ? "start" : _g, _h = _a.parent, parent = _h === void 0 ? document.body : _h, yAnchor = _a.yAnchor;
|
||||
var _j = target === "mouse"
|
||||
? mousePosition
|
||||
: getElementPosition(target, isTargetAbsolute), x = _j.x, y = _j.y, width = _j.width, height = _j.height, actualX = _j.actualX, actualY = _j.actualY;
|
||||
var elementWidth = element.offsetWidth;
|
||||
var elementHeight = element.offsetHeight;
|
||||
var windowWidth = parent.clientWidth;
|
||||
var windowHeight = parent.clientHeight - 20;
|
||||
var position = { top: 0, left: 0 };
|
||||
if (windowWidth - actualX < elementWidth) {
|
||||
var xDiff = actualX - x;
|
||||
position.left = windowWidth - elementWidth;
|
||||
position.left -= xDiff;
|
||||
}
|
||||
else {
|
||||
position.left = x;
|
||||
}
|
||||
if (width) {
|
||||
if (location === "right")
|
||||
position.left += width;
|
||||
else if (location === "left")
|
||||
position.left -= elementWidth;
|
||||
}
|
||||
if (windowHeight - actualY < elementHeight) {
|
||||
var yDiff = actualY - y;
|
||||
position.top = windowHeight - elementHeight;
|
||||
position.top -= yDiff;
|
||||
}
|
||||
else {
|
||||
position.top = y;
|
||||
}
|
||||
if (height) {
|
||||
if (location === "below")
|
||||
position.top += height;
|
||||
else if (location === "top")
|
||||
position.top -= height;
|
||||
}
|
||||
if (target !== "mouse" && align === "center" && elementWidth > 0) {
|
||||
position.left -= elementWidth / 2 - target.clientWidth / 2;
|
||||
}
|
||||
// Adjust menu height
|
||||
if (elementHeight > windowHeight - position.top) {
|
||||
element.style.maxHeight = "".concat(windowHeight - 20, "px");
|
||||
}
|
||||
if (yAnchor) {
|
||||
var anchorY = getElementPosition(yAnchor, isTargetAbsolute);
|
||||
position.top = anchorY.actualY - elementHeight;
|
||||
}
|
||||
position.top = position.top < 0 ? 0 : position.top;
|
||||
position.left = position.left < 0 ? 0 : position.left;
|
||||
position.top += yOffset;
|
||||
position.left += xOffset;
|
||||
return position;
|
||||
}
|
||||
function getMousePosition(e) {
|
||||
var posx = 0;
|
||||
var posy = 0;
|
||||
if (!e && window.event)
|
||||
e = window.event;
|
||||
if (e.pageX || e.pageY) {
|
||||
posx = e.pageX;
|
||||
posy = e.pageY;
|
||||
}
|
||||
else if (e.clientX || e.clientY) {
|
||||
posx =
|
||||
e.clientX +
|
||||
document.body.scrollLeft +
|
||||
document.documentElement.scrollLeft;
|
||||
posy =
|
||||
e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
||||
}
|
||||
return {
|
||||
x: posx,
|
||||
y: posy,
|
||||
actualY: posy,
|
||||
actualX: posx,
|
||||
};
|
||||
}
|
||||
export function getElementPosition(element, absolute) {
|
||||
var rect = element.getBoundingClientRect();
|
||||
var position = {
|
||||
x: element.offsetLeft,
|
||||
y: element.offsetTop,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
actualY: rect.y,
|
||||
actualX: rect.x,
|
||||
};
|
||||
if (absolute) {
|
||||
position.x = position.actualX;
|
||||
position.y = position.actualY;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
// function mapMenuItems<TData>(
|
||||
// items: MenuItem<TData>[],
|
||||
// data: TData
|
||||
// ): ResolvedMenuItem<TData>[] {
|
||||
// return items.reduce((prev, item) => {
|
||||
// const { key, onClick: _onClick, disabled, hidden, checked, type } = item;
|
||||
// const isHidden = resolveProp(hidden, data, item);
|
||||
// if (isHidden) return prev;
|
||||
// const isSeperator = type === "seperator";
|
||||
// if (isSeperator) {
|
||||
// prev.push({ isSeperator: true });
|
||||
// return prev;
|
||||
// }
|
||||
// const title = resolveProp(item.title, data, item);
|
||||
// const icon = resolveProp(item.icon, data, item);
|
||||
// const isChecked = resolveProp(checked, data, item);
|
||||
// const isDisabled = resolveProp(disabled, data, item);
|
||||
// const items = resolveProp(item.items, data, item);
|
||||
// const modifier = resolveProp(item.modifier, data, item);
|
||||
// const onClick =
|
||||
// typeof _onClick === "function" && _onClick.bind(this, data, item);
|
||||
// const tooltip =
|
||||
// isDisabled || resolveProp(item.tooltip, data, item) || title;
|
||||
// const hasSubmenu = items?.length > 0;
|
||||
// const menuItem: ResolvedMenuItem<TData> = {
|
||||
// type,
|
||||
// title,
|
||||
// key,
|
||||
// onClick,
|
||||
// tooltip,
|
||||
// isChecked,
|
||||
// isDisabled: !!isDisabled,
|
||||
// isHidden,
|
||||
// hasSubmenu,
|
||||
// icon,
|
||||
// modifier: modifier?.join("+"),
|
||||
// };
|
||||
// if (hasSubmenu)
|
||||
// menuItem.items = mapMenuItems(items, { ...data, parent: menuItem });
|
||||
// prev.push(menuItem);
|
||||
// return prev;
|
||||
// }, []);
|
||||
// }
|
||||
// function resolveProp<T, TData>(
|
||||
// prop: Resolvable<T, TData>,
|
||||
// data: any,
|
||||
// item: MenuItem<TData>
|
||||
// ): T {
|
||||
// if (typeof prop === "function" && (prop as any).isReactComponent) {
|
||||
// return prop as T;
|
||||
// }
|
||||
// return isResolverFunction<T, TData>(prop) ? prop(data, item) : prop;
|
||||
// }
|
||||
// function isResolverFunction<T, TData>(
|
||||
// prop: any
|
||||
// ): prop is ResolverFunction<T, TData> {
|
||||
// return typeof prop === "function";
|
||||
// }
|
||||
4
packages/editor/dist/components/toggle/index.d.ts
vendored
Normal file
4
packages/editor/dist/components/toggle/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/// <reference types="react" />
|
||||
import { ToggleProps } from "react-toggle";
|
||||
import "react-toggle/style.css";
|
||||
export declare function Toggle(props: ToggleProps): JSX.Element;
|
||||
18
packages/editor/dist/components/toggle/index.js
vendored
Normal file
18
packages/editor/dist/components/toggle/index.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import ReactToggle from "react-toggle";
|
||||
import "react-toggle/style.css";
|
||||
var css = ".react-toggle {\n display: flex;\n align-items: center;\n }\n \n .react-toggle-thumb {\n box-shadow: none;\n }\n \n .react-toggle-track {\n width: 30px;\n height: 18px;\n }\n \n .react-toggle-thumb {\n width: 16px;\n height: 16px;\n top: 0px;\n left: 1px;\n margin-top: 1px;\n }\n \n .react-toggle--checked .react-toggle-thumb {\n left: 13px;\n border-color: var(--primary);\n }\n \n .react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {\n box-shadow: none;\n }\n \n .react-toggle--focus .react-toggle-thumb {\n box-shadow: none;\n }\n ";
|
||||
export function Toggle(props) {
|
||||
return (_jsxs(_Fragment, { children: [_jsx("style", { children: css }), _jsx(ReactToggle, __assign({ size: 20, onChange: function () { }, icons: false }, props))] }));
|
||||
}
|
||||
1
packages/editor/dist/extensions/bulletlist/bulletlist.d.ts
vendored
Normal file
1
packages/editor/dist/extensions/bulletlist/bulletlist.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const BulletList: import("@tiptap/core").Node<import("@tiptap/extension-bullet-list").BulletListOptions, any>;
|
||||
19
packages/editor/dist/extensions/bulletlist/bulletlist.js
vendored
Normal file
19
packages/editor/dist/extensions/bulletlist/bulletlist.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import TiptapBulletList from "@tiptap/extension-bullet-list";
|
||||
export var BulletList = TiptapBulletList.extend({
|
||||
addAttributes: function () {
|
||||
return {
|
||||
listType: {
|
||||
default: null,
|
||||
parseHTML: function (element) { return element.style.listStyleType; },
|
||||
renderHTML: function (attributes) {
|
||||
if (!attributes.listType) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
style: "list-style-type: ".concat(attributes.listType),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
3
packages/editor/dist/extensions/bulletlist/index.d.ts
vendored
Normal file
3
packages/editor/dist/extensions/bulletlist/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { BulletList } from "./bullet-list";
|
||||
export * from "./bullet-list";
|
||||
export default BulletList;
|
||||
3
packages/editor/dist/extensions/bulletlist/index.js
vendored
Normal file
3
packages/editor/dist/extensions/bulletlist/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { BulletList } from "./bullet-list";
|
||||
export * from "./bullet-list";
|
||||
export default BulletList;
|
||||
22
packages/editor/dist/extensions/fontsize/fontsize.d.ts
vendored
Normal file
22
packages/editor/dist/extensions/fontsize/fontsize.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import "@tiptap/extension-text-style";
|
||||
declare type FontSizeOptions = {
|
||||
types: string[];
|
||||
defaultFontSize: number;
|
||||
};
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
fontSize: {
|
||||
/**
|
||||
* Set the font family
|
||||
*/
|
||||
setFontSize: (fontSize: string) => ReturnType;
|
||||
/**
|
||||
* Unset the font family
|
||||
*/
|
||||
unsetFontSize: () => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
export declare const FontSize: Extension<FontSizeOptions, any>;
|
||||
export {};
|
||||
49
packages/editor/dist/extensions/fontsize/fontsize.js
vendored
Normal file
49
packages/editor/dist/extensions/fontsize/fontsize.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import "@tiptap/extension-text-style";
|
||||
export var FontSize = Extension.create({
|
||||
name: "fontSize",
|
||||
defaultOptions: {
|
||||
types: ["textStyle"],
|
||||
defaultFontSize: 16,
|
||||
},
|
||||
addGlobalAttributes: function () {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
fontSize: {
|
||||
default: "".concat(this.options.defaultFontSize, "px"),
|
||||
parseHTML: function (element) { return element.style.fontSize; },
|
||||
renderHTML: function (attributes) {
|
||||
if (!attributes.fontSize) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
style: "font-size: ".concat(attributes.fontSize),
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
addCommands: function () {
|
||||
return {
|
||||
setFontSize: function (fontSize) {
|
||||
return function (_a) {
|
||||
var chain = _a.chain;
|
||||
return chain().setMark("textStyle", { fontSize: fontSize }).run();
|
||||
};
|
||||
},
|
||||
unsetFontSize: function () {
|
||||
return function (_a) {
|
||||
var chain = _a.chain;
|
||||
return chain()
|
||||
.setMark("textStyle", { fontSize: null })
|
||||
.removeEmptyTextStyle()
|
||||
.run();
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
3
packages/editor/dist/extensions/fontsize/index.d.ts
vendored
Normal file
3
packages/editor/dist/extensions/fontsize/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { FontSize } from "./font-size";
|
||||
export * from "./font-size";
|
||||
export default FontSize;
|
||||
3
packages/editor/dist/extensions/fontsize/index.js
vendored
Normal file
3
packages/editor/dist/extensions/fontsize/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { FontSize } from "./font-size";
|
||||
export * from "./font-size";
|
||||
export default FontSize;
|
||||
4
packages/editor/dist/extensions/image/component.d.ts
vendored
Normal file
4
packages/editor/dist/extensions/image/component.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/// <reference types="react" />
|
||||
import { ImageProps } from "rebass";
|
||||
import { NodeViewProps } from "@tiptap/react";
|
||||
export declare function ImageComponent(props: ImageProps & NodeViewProps): JSX.Element;
|
||||
129
packages/editor/dist/extensions/image/component.js
vendored
Normal file
129
packages/editor/dist/extensions/image/component.js
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Box, Flex, Image, Text } from "rebass";
|
||||
import { NodeViewWrapper } from "@tiptap/react";
|
||||
import { ThemeProvider } from "emotion-theming";
|
||||
import { Resizable } from "re-resizable";
|
||||
import { ToolButton } from "../../toolbar/components/tool-button";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Popup } from "../../toolbar/components/popup";
|
||||
import { Toggle } from "../../components/toggle";
|
||||
import { Input } from "@rebass/forms";
|
||||
export function ImageComponent(props) {
|
||||
var _a = props.node
|
||||
.attrs, src = _a.src, alt = _a.alt, title = _a.title, width = _a.width, height = _a.height, align = _a.align, float = _a.float;
|
||||
var editor = props.editor, updateAttributes = props.updateAttributes;
|
||||
var imageRef = useRef();
|
||||
var isActive = editor.isActive("image", { src: src });
|
||||
var _b = useState(), isToolbarVisible = _b[0], setIsToolbarVisible = _b[1];
|
||||
var theme = editor.storage.theme;
|
||||
useEffect(function () {
|
||||
setIsToolbarVisible(isActive);
|
||||
}, [isActive]);
|
||||
return (_jsx(NodeViewWrapper, { children: _jsx(ThemeProvider, __assign({ theme: theme }, { children: _jsx(Box, __assign({ sx: {
|
||||
display: float ? "block" : "flex",
|
||||
justifyContent: float
|
||||
? "stretch"
|
||||
: align === "center"
|
||||
? "center"
|
||||
: align === "left"
|
||||
? "start"
|
||||
: "end",
|
||||
} }, { children: _jsxs(Resizable, __assign({ style: {
|
||||
float: float ? (align === "left" ? "left" : "right") : "none",
|
||||
}, size: {
|
||||
height: height || "auto",
|
||||
width: width || "auto",
|
||||
}, maxWidth: "100%", onResizeStop: function (e, direction, ref, d) {
|
||||
updateAttributes({
|
||||
width: ref.clientWidth,
|
||||
height: ref.clientHeight,
|
||||
});
|
||||
}, lockAspectRatio: true }, { children: [_jsx(Flex, __assign({ sx: { position: "relative", justifyContent: "end" } }, { children: isToolbarVisible && (_jsx(ImageToolbar, { editor: editor, float: float, align: align, height: height || 0, width: width || 0 })) })), _jsx(Image, __assign({ ref: imageRef, src: src, alt: alt, title: title, width: "100%", height: "100%", sx: {
|
||||
border: isActive
|
||||
? "2px solid var(--primary)"
|
||||
: "2px solid transparent",
|
||||
borderRadius: "default",
|
||||
} }, props))] })) })) })) }));
|
||||
}
|
||||
function ImageToolbar(props) {
|
||||
var editor = props.editor, float = props.float, height = props.height, width = props.width;
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var onSizeChange = useCallback(function (newWidth, newHeight) {
|
||||
var size = newWidth
|
||||
? {
|
||||
width: newWidth,
|
||||
height: newWidth * (height / width),
|
||||
}
|
||||
: newHeight
|
||||
? {
|
||||
width: newHeight * (width / height),
|
||||
height: newHeight,
|
||||
}
|
||||
: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
editor.chain().setImageSize(size).run();
|
||||
}, [width, height]);
|
||||
return (_jsxs(Flex, __assign({ sx: {
|
||||
flexDirection: "column",
|
||||
position: "absolute",
|
||||
top: -40,
|
||||
mb: 2,
|
||||
zIndex: 9999,
|
||||
alignItems: "end",
|
||||
} }, { children: [_jsxs(Flex, __assign({ sx: {
|
||||
bg: "background",
|
||||
boxShadow: "menu",
|
||||
flexWrap: "nowrap",
|
||||
borderRadius: "default",
|
||||
mb: 2,
|
||||
} }, { children: [_jsxs(Flex, __assign({ className: "toolbar-group", sx: {
|
||||
pr: 1,
|
||||
mr: 1,
|
||||
borderRight: "1px solid var(--border)",
|
||||
":last-of-type": { mr: 0, pr: 0, borderRight: "none" },
|
||||
} }, { children: [_jsx(ToolButton, { toggled: false, title: "Align left", id: "alignLeft", icon: "alignLeft", onClick: function () {
|
||||
return editor.chain().focus().setImageAlignment({ align: "left" }).run();
|
||||
} }), float ? null : (_jsx(ToolButton, { toggled: false, title: "Align center", id: "alignCenter", icon: "alignCenter", onClick: function () {
|
||||
return editor
|
||||
.chain()
|
||||
.focus()
|
||||
.setImageAlignment({ align: "center" })
|
||||
.run();
|
||||
} })), _jsx(ToolButton, { toggled: false, title: "Align right", id: "alignRight", icon: "alignRight", onClick: function () {
|
||||
return editor.chain().focus().setImageAlignment({ align: "right" }).run();
|
||||
} })] })), _jsx(Flex, __assign({ className: "toolbar-group", sx: {
|
||||
pr: 1,
|
||||
mr: 1,
|
||||
borderRight: "1px solid var(--border)",
|
||||
":last-of-type": { mr: 0, pr: 0, borderRight: "none" },
|
||||
} }, { children: _jsx(ToolButton, { toggled: isOpen, title: "Image properties", id: "imageProperties", icon: "more", onClick: function () { return setIsOpen(function (s) { return !s; }); } }) }))] })), isOpen && (_jsx(Popup, __assign({ title: "Image properties", action: {
|
||||
icon: "close",
|
||||
onClick: function () {
|
||||
setIsOpen(false);
|
||||
},
|
||||
} }, { children: _jsxs(Flex, __assign({ sx: { width: 200, flexDirection: "column", p: 1 } }, { children: [_jsxs(Flex, __assign({ sx: { justifyContent: "space-between", alignItems: "center" } }, { children: [_jsx(Text, __assign({ variant: "body" }, { children: "Floating?" })), _jsx(Toggle, { checked: float, onClick: function () {
|
||||
return editor
|
||||
.chain()
|
||||
.setImageAlignment({ float: !float, align: "left" })
|
||||
.run();
|
||||
} })] })), _jsxs(Flex, __assign({ sx: { alignItems: "center", mt: 2 } }, { children: [_jsx(Input, { type: "number", placeholder: "Width", value: width, sx: {
|
||||
mr: 2,
|
||||
p: 1,
|
||||
fontSize: "body",
|
||||
}, onChange: function (e) { return onSizeChange(e.target.valueAsNumber); } }), _jsx(Input, { type: "number", placeholder: "Height", value: height, sx: { p: 1, fontSize: "body" }, onChange: function (e) {
|
||||
return onSizeChange(undefined, e.target.valueAsNumber);
|
||||
} })] }))] })) })))] })));
|
||||
}
|
||||
33
packages/editor/dist/extensions/image/image.d.ts
vendored
Normal file
33
packages/editor/dist/extensions/image/image.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Node } from "@tiptap/core";
|
||||
export interface ImageOptions {
|
||||
inline: boolean;
|
||||
allowBase64: boolean;
|
||||
HTMLAttributes: Record<string, any>;
|
||||
}
|
||||
export declare type ImageAttributes = Partial<ImageSizeOptions> & {
|
||||
src: string;
|
||||
alt?: string;
|
||||
title?: string;
|
||||
};
|
||||
export declare type ImageAlignmentOptions = {
|
||||
float?: boolean;
|
||||
align?: "center" | "left" | "right";
|
||||
};
|
||||
export declare type ImageSizeOptions = {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
image: {
|
||||
/**
|
||||
* Add an image
|
||||
*/
|
||||
setImage: (options: ImageAttributes) => ReturnType;
|
||||
setImageAlignment: (options: ImageAlignmentOptions) => ReturnType;
|
||||
setImageSize: (options: ImageSizeOptions) => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
export declare const inputRegex: RegExp;
|
||||
export declare const ImageNode: Node<ImageOptions, any>;
|
||||
108
packages/editor/dist/extensions/image/image.js
vendored
Normal file
108
packages/editor/dist/extensions/image/image.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
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);
|
||||
};
|
||||
import { Node, nodeInputRule, mergeAttributes } from "@tiptap/core";
|
||||
import { ReactNodeViewRenderer } from "@tiptap/react";
|
||||
import { ImageComponent } from "./component";
|
||||
export var inputRegex = /(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/;
|
||||
export var ImageNode = Node.create({
|
||||
name: "image",
|
||||
addOptions: function () {
|
||||
return {
|
||||
inline: false,
|
||||
allowBase64: false,
|
||||
HTMLAttributes: {},
|
||||
};
|
||||
},
|
||||
inline: function () {
|
||||
return this.options.inline;
|
||||
},
|
||||
group: function () {
|
||||
return this.options.inline ? "inline" : "block";
|
||||
},
|
||||
draggable: true,
|
||||
addAttributes: function () {
|
||||
return {
|
||||
src: {
|
||||
default: null,
|
||||
},
|
||||
alt: {
|
||||
default: null,
|
||||
},
|
||||
title: {
|
||||
default: null,
|
||||
},
|
||||
width: { default: null },
|
||||
height: { default: null },
|
||||
float: {
|
||||
default: false,
|
||||
},
|
||||
align: { default: "left" },
|
||||
};
|
||||
},
|
||||
parseHTML: function () {
|
||||
return [
|
||||
{
|
||||
tag: this.options.allowBase64
|
||||
? "img[src]"
|
||||
: 'img[src]:not([src^="data:"])',
|
||||
},
|
||||
];
|
||||
},
|
||||
renderHTML: function (_a) {
|
||||
var HTMLAttributes = _a.HTMLAttributes;
|
||||
return [
|
||||
"img",
|
||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
||||
];
|
||||
},
|
||||
addNodeView: function () {
|
||||
return ReactNodeViewRenderer(ImageComponent);
|
||||
},
|
||||
addCommands: function () {
|
||||
var _this = this;
|
||||
return {
|
||||
setImage: function (options) {
|
||||
return function (_a) {
|
||||
var commands = _a.commands;
|
||||
return commands.insertContent({
|
||||
type: _this.name,
|
||||
attrs: options,
|
||||
});
|
||||
};
|
||||
},
|
||||
setImageAlignment: function (options) {
|
||||
return function (_a) {
|
||||
var commands = _a.commands;
|
||||
return commands.updateAttributes(_this.name, __assign({}, options));
|
||||
};
|
||||
},
|
||||
setImageSize: function (options) {
|
||||
return function (_a) {
|
||||
var commands = _a.commands;
|
||||
return commands.updateAttributes(_this.name, __assign({}, options));
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
addInputRules: function () {
|
||||
return [
|
||||
nodeInputRule({
|
||||
find: inputRegex,
|
||||
type: this.type,
|
||||
getAttributes: function (match) {
|
||||
var alt = match[2], src = match[3], title = match[4];
|
||||
return { src: src, alt: alt, title: title };
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
1
packages/editor/dist/extensions/image/index.d.ts
vendored
Normal file
1
packages/editor/dist/extensions/image/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./image";
|
||||
1
packages/editor/dist/extensions/image/index.js
vendored
Normal file
1
packages/editor/dist/extensions/image/index.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./image";
|
||||
3
packages/editor/dist/extensions/orderedlist/index.d.ts
vendored
Normal file
3
packages/editor/dist/extensions/orderedlist/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { OrderedList } from "./ordered-list";
|
||||
export * from "./ordered-list";
|
||||
export default OrderedList;
|
||||
3
packages/editor/dist/extensions/orderedlist/index.js
vendored
Normal file
3
packages/editor/dist/extensions/orderedlist/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { OrderedList } from "./ordered-list";
|
||||
export * from "./ordered-list";
|
||||
export default OrderedList;
|
||||
1
packages/editor/dist/extensions/orderedlist/orderedlist.d.ts
vendored
Normal file
1
packages/editor/dist/extensions/orderedlist/orderedlist.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const OrderedList: import("@tiptap/core").Node<import("@tiptap/extension-ordered-list").OrderedListOptions, any>;
|
||||
19
packages/editor/dist/extensions/orderedlist/orderedlist.js
vendored
Normal file
19
packages/editor/dist/extensions/orderedlist/orderedlist.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import TiptapOrderedList from "@tiptap/extension-ordered-list";
|
||||
export var OrderedList = TiptapOrderedList.extend({
|
||||
addAttributes: function () {
|
||||
return {
|
||||
listType: {
|
||||
default: null,
|
||||
parseHTML: function (element) { return element.style.listStyleType; },
|
||||
renderHTML: function (attributes) {
|
||||
if (!attributes.listType) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
style: "list-style-type: ".concat(attributes.listType),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
3
packages/editor/dist/extensions/tablecell/index.d.ts
vendored
Normal file
3
packages/editor/dist/extensions/tablecell/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { TableCell } from "./table-cell";
|
||||
export * from "./table-cell";
|
||||
export default TableCell;
|
||||
3
packages/editor/dist/extensions/tablecell/index.js
vendored
Normal file
3
packages/editor/dist/extensions/tablecell/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { TableCell } from "./table-cell";
|
||||
export * from "./table-cell";
|
||||
export default TableCell;
|
||||
1
packages/editor/dist/extensions/tablecell/tablecell.d.ts
vendored
Normal file
1
packages/editor/dist/extensions/tablecell/tablecell.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare const TableCell: import("@tiptap/core").Node<import("@tiptap/extension-table-cell").TableCellOptions, any>;
|
||||
37
packages/editor/dist/extensions/tablecell/tablecell.js
vendored
Normal file
37
packages/editor/dist/extensions/tablecell/tablecell.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
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);
|
||||
};
|
||||
import TiptapTableCell from "@tiptap/extension-table-cell";
|
||||
export var TableCell = TiptapTableCell.extend({
|
||||
addAttributes: function () {
|
||||
var _a;
|
||||
return __assign(__assign({}, (_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)), { backgroundColor: addStyleAttribute("backgroundColor", "background-color"), color: addStyleAttribute("color", "color"), borderWidth: addStyleAttribute("borderWidth", "border-width", "px"), borderStyle: addStyleAttribute("borderStyle", "border-style"), borderColor: addStyleAttribute("borderColor", "border-color") });
|
||||
},
|
||||
});
|
||||
function addStyleAttribute(name, cssName, unit) {
|
||||
return {
|
||||
default: null,
|
||||
parseHTML: function (element) {
|
||||
var _a;
|
||||
return unit
|
||||
? (_a = element.style[name]) === null || _a === void 0 ? void 0 : _a.toString().replace(unit, "")
|
||||
: element.style[name];
|
||||
},
|
||||
renderHTML: function (attributes) {
|
||||
if (!attributes[name]) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
style: "".concat(cssName, ": ").concat(attributes[name]).concat(unit || ""),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
3
packages/editor/dist/extensions/textdirection/index.d.ts
vendored
Normal file
3
packages/editor/dist/extensions/textdirection/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { TextDirection } from "./text-direction";
|
||||
export * from "./text-direction";
|
||||
export default TextDirection;
|
||||
3
packages/editor/dist/extensions/textdirection/index.js
vendored
Normal file
3
packages/editor/dist/extensions/textdirection/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { TextDirection } from "./text-direction";
|
||||
export * from "./text-direction";
|
||||
export default TextDirection;
|
||||
19
packages/editor/dist/extensions/textdirection/textdirection.d.ts
vendored
Normal file
19
packages/editor/dist/extensions/textdirection/textdirection.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import "@tiptap/extension-text-style";
|
||||
declare type TextDirectionOptions = {
|
||||
types: string[];
|
||||
defaultDirection: TextDirections;
|
||||
};
|
||||
declare type TextDirections = "ltr" | "rtl";
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
textDirection: {
|
||||
/**
|
||||
* Set the font family
|
||||
*/
|
||||
setTextDirection: (direction: TextDirections) => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
export declare const TextDirection: Extension<TextDirectionOptions, any>;
|
||||
export {};
|
||||
43
packages/editor/dist/extensions/textdirection/textdirection.js
vendored
Normal file
43
packages/editor/dist/extensions/textdirection/textdirection.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import "@tiptap/extension-text-style";
|
||||
export var TextDirection = Extension.create({
|
||||
name: "textDirection",
|
||||
defaultOptions: {
|
||||
types: ["paragraph", "heading"],
|
||||
defaultDirection: "ltr",
|
||||
},
|
||||
addGlobalAttributes: function () {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
textDirection: {
|
||||
default: this.options.defaultDirection,
|
||||
parseHTML: function (element) { return element.dir; },
|
||||
renderHTML: function (attributes) {
|
||||
if (!attributes.textDirection) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
dir: attributes.textDirection,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
addCommands: function () {
|
||||
var _this = this;
|
||||
return {
|
||||
setTextDirection: function (direction) {
|
||||
return function (_a) {
|
||||
var commands = _a.commands;
|
||||
return _this.options.types.every(function (type) {
|
||||
return commands.updateAttributes(type, { textDirection: direction });
|
||||
});
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
6
packages/editor/dist/index.d.ts
vendored
Normal file
6
packages/editor/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="react" />
|
||||
import { EditorOptions } from "@tiptap/react";
|
||||
import Toolbar from "./toolbar";
|
||||
import { ThemeConfig } from "@notesnook/theme/dist/theme/types";
|
||||
declare const useTiptap: (options?: Partial<EditorOptions & ThemeConfig>, deps?: import("react").DependencyList | undefined) => import("@tiptap/react").Editor | null;
|
||||
export { useTiptap, Toolbar };
|
||||
108
packages/editor/dist/index.js
vendored
Normal file
108
packages/editor/dist/index.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
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 __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import CharacterCount from "@tiptap/extension-character-count";
|
||||
import Placeholder from "@tiptap/extension-placeholder";
|
||||
import Underline from "@tiptap/extension-underline";
|
||||
import { useEditor } from "@tiptap/react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { useMemo } from "react";
|
||||
import { EditorView } from "prosemirror-view";
|
||||
import Toolbar from "./toolbar";
|
||||
import TextAlign from "@tiptap/extension-text-align";
|
||||
import Subscript from "@tiptap/extension-subscript";
|
||||
import Superscript from "@tiptap/extension-superscript";
|
||||
import FontSize from "./extensions/font-size";
|
||||
import TextDirection from "./extensions/text-direction";
|
||||
import TextStyle from "@tiptap/extension-text-style";
|
||||
import FontFamily from "@tiptap/extension-font-family";
|
||||
import BulletList from "./extensions/bullet-list";
|
||||
import OrderedList from "./extensions/ordered-list";
|
||||
import Highlight from "@tiptap/extension-highlight";
|
||||
import Color from "@tiptap/extension-color";
|
||||
import Link from "@tiptap/extension-link";
|
||||
import Table from "@tiptap/extension-table";
|
||||
import TableRow from "@tiptap/extension-table-row";
|
||||
import TableCell from "./extensions/table-cell";
|
||||
import TableHeader from "@tiptap/extension-table-header";
|
||||
import { ImageNode } from "./extensions/image";
|
||||
import { useTheme } from "@notesnook/theme";
|
||||
EditorView.prototype.updateState = function updateState(state) {
|
||||
if (!this.docView)
|
||||
return; // This prevents the matchesNode error on hot reloads
|
||||
this.updateStateInner(state, this.state.plugins != state.plugins);
|
||||
};
|
||||
var useTiptap = function (options, deps) {
|
||||
if (options === void 0) { options = {}; }
|
||||
var theme = options.theme, accent = options.accent, scale = options.scale, onCreate = options.onCreate, restOptions = __rest(options, ["theme", "accent", "scale", "onCreate"]);
|
||||
var defaultOptions = useMemo(function () { return ({
|
||||
extensions: [
|
||||
TextStyle,
|
||||
StarterKit,
|
||||
CharacterCount,
|
||||
Underline,
|
||||
Subscript,
|
||||
Superscript,
|
||||
FontSize,
|
||||
TextDirection,
|
||||
FontFamily,
|
||||
BulletList,
|
||||
OrderedList,
|
||||
Link,
|
||||
ImageNode,
|
||||
Table.configure({
|
||||
resizable: true,
|
||||
allowTableNodeSelection: true,
|
||||
}),
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
Highlight.configure({
|
||||
multicolor: true,
|
||||
}),
|
||||
Color,
|
||||
TextAlign.configure({
|
||||
types: ["heading", "paragraph"],
|
||||
alignments: ["left", "right", "center", "justify"],
|
||||
defaultAlignment: "left",
|
||||
}),
|
||||
Placeholder.configure({
|
||||
placeholder: "Start writing your note...",
|
||||
}),
|
||||
],
|
||||
onCreate: function (_a) {
|
||||
var editor = _a.editor;
|
||||
if (theme && accent && scale) {
|
||||
editor.storage.theme = useTheme({ theme: theme, accent: accent, scale: scale });
|
||||
}
|
||||
if (onCreate)
|
||||
onCreate({ editor: editor });
|
||||
},
|
||||
}); }, [theme, accent, scale, onCreate]);
|
||||
var editor = useEditor(__assign(__assign({}, defaultOptions), restOptions), deps);
|
||||
/**
|
||||
* Add editor to global for use in React Native.
|
||||
*/
|
||||
global.editor = editor;
|
||||
return editor;
|
||||
};
|
||||
export { useTiptap, Toolbar };
|
||||
8
packages/editor/dist/toolbar/components/dropdown.d.ts
vendored
Normal file
8
packages/editor/dist/toolbar/components/dropdown.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/// <reference types="react" />
|
||||
import { MenuItem } from "../../components/menu/types";
|
||||
declare type DropdownProps = {
|
||||
selectedItem: string | JSX.Element;
|
||||
items: MenuItem[];
|
||||
};
|
||||
export declare function Dropdown(props: DropdownProps): JSX.Element;
|
||||
export {};
|
||||
42
packages/editor/dist/toolbar/components/dropdown.js
vendored
Normal file
42
packages/editor/dist/toolbar/components/dropdown.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { useRef, useState } from "react";
|
||||
import { Button, Text } from "rebass";
|
||||
import { Icon } from "./icon";
|
||||
import { Icons } from "../icons";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
export function Dropdown(props) {
|
||||
var items = props.items, selectedItem = props.selectedItem;
|
||||
var buttonRef = useRef(null);
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
return (_jsxs(_Fragment, { children: [_jsxs(Button, __assign({ ref: buttonRef, sx: {
|
||||
p: 1,
|
||||
m: 0,
|
||||
bg: isOpen ? "hover" : "transparent",
|
||||
mr: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
":hover": { bg: "hover" },
|
||||
":last-of-type": {
|
||||
mr: 0,
|
||||
},
|
||||
}, onClick: function () { return setIsOpen(function (s) { return !s; }); } }, { children: [typeof selectedItem === "string" ? (_jsx(Text, __assign({ sx: { fontSize: 12, mr: 1, color: "text" } }, { children: selectedItem }))) : (selectedItem), _jsx(Icon, { path: Icons.chevronDown, size: 16, color: "text" })] })), _jsx(MenuPresenter, { options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: buttonRef.current || undefined,
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
yOffset: 5,
|
||||
},
|
||||
}, isOpen: isOpen, items: items, onClose: function () { return setIsOpen(false); } })] }));
|
||||
}
|
||||
14
packages/editor/dist/toolbar/components/icon.d.ts
vendored
Normal file
14
packages/editor/dist/toolbar/components/icon.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <reference types="react" />
|
||||
import { SchemeColors } from "@notesnook/theme/dist/theme/colorscheme";
|
||||
import { FlexProps } from "rebass";
|
||||
declare type IconProps = {
|
||||
title?: string;
|
||||
path: string;
|
||||
size?: number;
|
||||
color?: keyof SchemeColors;
|
||||
stroke?: string;
|
||||
rotate?: boolean;
|
||||
};
|
||||
export declare type NNIconProps = FlexProps & IconProps;
|
||||
export declare function Icon(props: NNIconProps): JSX.Element;
|
||||
export {};
|
||||
41
packages/editor/dist/toolbar/components/icon.js
vendored
Normal file
41
packages/editor/dist/toolbar/components/icon.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
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 __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import MDIIcon from "@mdi/react";
|
||||
import { useTheme } from "emotion-theming";
|
||||
import { Flex } from "rebass";
|
||||
function MDIIconWrapper(_a) {
|
||||
var title = _a.title, path = _a.path, _b = _a.size, size = _b === void 0 ? 24 : _b, _c = _a.color, color = _c === void 0 ? "icon" : _c, stroke = _a.stroke, rotate = _a.rotate;
|
||||
var theme = useTheme();
|
||||
var themedColor = theme.colors
|
||||
? theme.colors[color]
|
||||
: color;
|
||||
return (_jsx(MDIIcon, { title: title, path: path, size: size + "px", style: {
|
||||
strokeWidth: stroke || "0px",
|
||||
stroke: themedColor,
|
||||
}, color: themedColor, spin: rotate }));
|
||||
}
|
||||
export function Icon(props) {
|
||||
var sx = props.sx, title = props.title, color = props.color, size = props.size, stroke = props.stroke, rotate = props.rotate, path = props.path, restProps = __rest(props, ["sx", "title", "color", "size", "stroke", "rotate", "path"]);
|
||||
return (_jsx(Flex, __assign({ sx: __assign({ flexShrink: 0, justifyContent: "center", alignItems: "center" }, sx) }, restProps, { children: _jsx(MDIIconWrapper, { title: title, path: path, rotate: rotate, color: color, stroke: stroke, size: size }) })));
|
||||
}
|
||||
17
packages/editor/dist/toolbar/components/popup.d.ts
vendored
Normal file
17
packages/editor/dist/toolbar/components/popup.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { ButtonProps } from "rebass";
|
||||
import { IconNames } from "../icons";
|
||||
import { PropsWithChildren } from "react";
|
||||
import { SchemeColors } from "@notesnook/theme/dist/theme/colorscheme";
|
||||
declare type PopupProps = {
|
||||
title?: string;
|
||||
action?: PopupButtonProps;
|
||||
};
|
||||
export declare function Popup(props: PropsWithChildren<PopupProps>): JSX.Element;
|
||||
declare type PopupButtonProps = ButtonProps & {
|
||||
text?: string;
|
||||
loading?: boolean;
|
||||
icon?: IconNames;
|
||||
iconSize?: number;
|
||||
iconColor?: keyof SchemeColors;
|
||||
};
|
||||
export {};
|
||||
45
packages/editor/dist/toolbar/components/popup.js
vendored
Normal file
45
packages/editor/dist/toolbar/components/popup.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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 __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Button, Flex, Text } from "rebass";
|
||||
import { Icon } from "./icon";
|
||||
import { Icons } from "../icons";
|
||||
export function Popup(props) {
|
||||
var title = props.title, action = props.action, children = props.children;
|
||||
return (_jsxs(Flex, __assign({ sx: {
|
||||
bg: "background",
|
||||
flexDirection: "column",
|
||||
borderRadius: "default",
|
||||
border: "1px solid var(--border)",
|
||||
boxShadow: "menu",
|
||||
} }, { children: [title && (_jsxs(Flex, __assign({ sx: {
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
mx: 1,
|
||||
mt: 1,
|
||||
} }, { children: [_jsx(Text, __assign({ variant: "subtitle" }, { children: title })), action && (_jsx(PopupButton, __assign({ "data-test-id": "popup-no", color: "text" }, action)))] }))), children] })));
|
||||
}
|
||||
function PopupButton(props) {
|
||||
var text = props.text, loading = props.loading, icon = props.icon, iconColor = props.iconColor, iconSize = props.iconSize, restProps = __rest(props, ["text", "loading", "icon", "iconColor", "iconSize"]);
|
||||
return (_jsx(Button, __assign({ variant: "dialog", sx: { p: 1, px: 2 } }, restProps, { children: loading ? (_jsx(Icon, { path: Icons.loading, size: 16, rotate: true, color: "primary" })) : icon ? (_jsx(Icon, { path: Icons[icon], size: iconSize || 18, color: iconColor || "icon" })) : (text) })));
|
||||
}
|
||||
13
packages/editor/dist/toolbar/components/toolbutton.d.ts
vendored
Normal file
13
packages/editor/dist/toolbar/components/toolbutton.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { SchemeColors } from "@notesnook/theme/dist/theme/colorscheme";
|
||||
import React from "react";
|
||||
import { ButtonProps } from "rebass";
|
||||
import { IconNames } from "../icons";
|
||||
declare type ToolButtonProps = ButtonProps & {
|
||||
icon: IconNames;
|
||||
iconColor?: keyof SchemeColors;
|
||||
iconSize?: number;
|
||||
toggled: boolean;
|
||||
buttonRef?: React.Ref<HTMLButtonElement>;
|
||||
};
|
||||
export declare function ToolButton(props: ToolButtonProps): JSX.Element;
|
||||
export {};
|
||||
32
packages/editor/dist/toolbar/components/toolbutton.js
vendored
Normal file
32
packages/editor/dist/toolbar/components/toolbutton.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
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 __rest = (this && this.__rest) || function (s, e) {
|
||||
var t = {};
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
||||
t[p] = s[p];
|
||||
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
||||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
||||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
||||
t[p[i]] = s[p[i]];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { Button } from "rebass";
|
||||
import { Icons } from "../icons";
|
||||
import { Icon } from "./icon";
|
||||
export 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, buttonProps = __rest(props, ["id", "icon", "iconSize", "iconColor", "toggled", "sx", "buttonRef"]);
|
||||
return (_jsx(Button, __assign({ ref: buttonRef, tabIndex: -1, id: "tool-".concat(id), sx: __assign({ p: 1, m: 0, bg: toggled ? "hover" : "transparent", mr: 1, ":hover": { bg: "hover" }, ":last-of-type": {
|
||||
mr: 0,
|
||||
} }, sx) }, buttonProps, { children: _jsx(Icon, { path: Icons[icon], color: iconColor || "text", size: iconSize || 18 }) })));
|
||||
}
|
||||
3
packages/editor/dist/toolbar/floatingmenus/index.d.ts
vendored
Normal file
3
packages/editor/dist/toolbar/floatingmenus/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="react" />
|
||||
import { FloatingMenuProps } from "./types";
|
||||
export declare function EditorFloatingMenus(props: FloatingMenuProps): JSX.Element;
|
||||
16
packages/editor/dist/toolbar/floatingmenus/index.js
vendored
Normal file
16
packages/editor/dist/toolbar/floatingmenus/index.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { TableRowFloatingMenu, TableColumnFloatingMenu } from "./table";
|
||||
export function EditorFloatingMenus(props) {
|
||||
return (_jsxs(_Fragment, { children: [_jsx(TableRowFloatingMenu, __assign({}, props)), _jsx(TableColumnFloatingMenu, __assign({}, props))] }));
|
||||
}
|
||||
4
packages/editor/dist/toolbar/floatingmenus/table.d.ts
vendored
Normal file
4
packages/editor/dist/toolbar/floatingmenus/table.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/// <reference types="react" />
|
||||
import { FloatingMenuProps } from "./types";
|
||||
export declare function TableRowFloatingMenu(props: FloatingMenuProps): JSX.Element | null;
|
||||
export declare function TableColumnFloatingMenu(props: FloatingMenuProps): JSX.Element | null;
|
||||
427
packages/editor/dist/toolbar/floatingmenus/table.js
vendored
Normal file
427
packages/editor/dist/toolbar/floatingmenus/table.js
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { Slider } from "@rebass/forms";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Flex, Text } from "rebass";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { Popup } from "../components/popup";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
import { ColorPicker, DEFAULT_COLORS } from "../tools/colors";
|
||||
import { selectedRect } from "prosemirror-tables";
|
||||
export function TableRowFloatingMenu(props) {
|
||||
var editor = props.editor;
|
||||
var theme = editor.storage.theme;
|
||||
var _a = useState(null), position = _a[0], setPosition = _a[1];
|
||||
var _b = useState(false), isMenuOpen = _b[0], setIsMenuOpen = _b[1];
|
||||
useEffect(function () {
|
||||
var _a;
|
||||
if (!editor.isActive("tableRow"))
|
||||
return;
|
||||
var $from = editor.state.selection.$from;
|
||||
var selectedNode = $from.node();
|
||||
var pos = selectedNode.isTextblock ? $from.before() : $from.pos;
|
||||
var currentRow = (_a = editor.view.nodeDOM(pos)) === null || _a === void 0 ? void 0 : _a.closest("tr");
|
||||
if (!currentRow)
|
||||
return;
|
||||
setPosition(function (old) {
|
||||
if ((old === null || old === void 0 ? void 0 : old.target) === currentRow)
|
||||
return old;
|
||||
return {
|
||||
isTargetAbsolute: true,
|
||||
location: "left",
|
||||
xOffset: -5,
|
||||
target: currentRow,
|
||||
// parent: editor.view.dom as HTMLElement,
|
||||
};
|
||||
});
|
||||
}, [editor.state.selection]);
|
||||
if (!position)
|
||||
return null;
|
||||
return (_jsxs(MenuPresenter, __assign({ isOpen: true, items: [], onClose: function () { }, options: {
|
||||
type: "autocomplete",
|
||||
position: position,
|
||||
} }, { children: [_jsxs(Flex, __assign({ sx: {
|
||||
bg: "background",
|
||||
flexWrap: "nowrap",
|
||||
borderRadius: "default",
|
||||
opacity: isMenuOpen ? 1 : 0.3,
|
||||
":hover": {
|
||||
opacity: 1,
|
||||
},
|
||||
} }, { children: [_jsx(ToolButton, { toggled: isMenuOpen, title: "Row properties", id: "properties", icon: "more", onClick: function () { return setIsMenuOpen(true); }, iconSize: 16, sx: { mr: 0, p: "3px", borderRadius: "small" } }), _jsx(ToolButton, { toggled: false, title: "Insert row below", id: "insertRowBelow", icon: "insertRowBelow", onClick: function () { return editor.chain().focus().addRowAfter().run(); }, sx: { mr: 0, p: "3px", borderRadius: "small" }, iconSize: 16 })] })), _jsx(MenuPresenter, { isOpen: isMenuOpen, onClose: function () {
|
||||
setIsMenuOpen(false);
|
||||
editor.commands.focus();
|
||||
}, options: {
|
||||
type: "menu",
|
||||
position: {},
|
||||
}, items: [
|
||||
{
|
||||
key: "addRowAbove",
|
||||
type: "menuitem",
|
||||
title: "Add row above",
|
||||
onClick: function () { return editor.chain().focus().addRowBefore().run(); },
|
||||
icon: "insertRowAbove",
|
||||
},
|
||||
{
|
||||
key: "moveRowUp",
|
||||
type: "menuitem",
|
||||
title: "Move row up",
|
||||
onClick: function () { return moveRowUp(editor); },
|
||||
icon: "moveRowUp",
|
||||
},
|
||||
{
|
||||
key: "moveRowDown",
|
||||
type: "menuitem",
|
||||
title: "Move row down",
|
||||
onClick: function () { return moveRowDown(editor); },
|
||||
icon: "moveRowDown",
|
||||
},
|
||||
{
|
||||
key: "deleteRow",
|
||||
type: "menuitem",
|
||||
title: "Delete row",
|
||||
onClick: function () { return editor.chain().focus().deleteRow().run(); },
|
||||
icon: "deleteRow",
|
||||
},
|
||||
] })] })));
|
||||
}
|
||||
export function TableColumnFloatingMenu(props) {
|
||||
var _this = this;
|
||||
var editor = props.editor;
|
||||
var _a = useState(null), position = _a[0], setPosition = _a[1];
|
||||
var _b = useState(false), isMenuOpen = _b[0], setIsMenuOpen = _b[1];
|
||||
var _c = useState(false), showCellProps = _c[0], setShowCellProps = _c[1];
|
||||
var _d = useState(null), menuPosition = _d[0], setMenuPosition = _d[1];
|
||||
useEffect(function () {
|
||||
var _a;
|
||||
if (!editor.isActive("tableRow"))
|
||||
return;
|
||||
var $from = editor.state.selection.$from;
|
||||
var selectedNode = $from.node();
|
||||
var pos = selectedNode.isTextblock ? $from.before() : $from.pos;
|
||||
var currentCell = (_a = editor.view.nodeDOM(pos)) === null || _a === void 0 ? void 0 : _a.closest("td,th");
|
||||
var currentTable = currentCell === null || currentCell === void 0 ? void 0 : currentCell.closest("table");
|
||||
if (!currentCell || !currentTable)
|
||||
return;
|
||||
setPosition(function (old) {
|
||||
if ((old === null || old === void 0 ? void 0 : old.target) === currentCell)
|
||||
return old;
|
||||
return {
|
||||
isTargetAbsolute: true,
|
||||
location: "top",
|
||||
align: "center",
|
||||
yAnchor: currentTable,
|
||||
yOffset: -2,
|
||||
target: currentCell,
|
||||
};
|
||||
});
|
||||
}, [editor.state.selection]);
|
||||
if (!position)
|
||||
return null;
|
||||
return (_jsxs(MenuPresenter, __assign({ isOpen: true, items: [], onClose: function () { }, options: {
|
||||
type: "autocomplete",
|
||||
position: position,
|
||||
} }, { children: [_jsxs(Flex, __assign({ sx: {
|
||||
bg: "background",
|
||||
flexWrap: "nowrap",
|
||||
borderRadius: "default",
|
||||
opacity: isMenuOpen || showCellProps ? 1 : 0.3,
|
||||
":hover": {
|
||||
opacity: 1,
|
||||
},
|
||||
} }, { children: [_jsx(ToolButton, { toggled: isMenuOpen, title: "Column properties", id: "properties", icon: "more", onClick: function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
||||
return [2 /*return*/, setIsMenuOpen(true)];
|
||||
}); }); }, iconSize: 16, sx: { mr: 0, p: "3px", borderRadius: "small" } }), _jsx(ToolButton, { toggled: false, title: "Insert column right", id: "insertColumnRight", icon: "insertColumnRight", onClick: function () { return editor.chain().focus().addColumnAfter().run(); }, sx: { mr: 0, p: "3px", borderRadius: "small" }, iconSize: 16 })] })), _jsx(MenuPresenter, { isOpen: isMenuOpen, onClose: function () {
|
||||
setIsMenuOpen(false);
|
||||
editor.commands.focus();
|
||||
}, options: {
|
||||
type: "menu",
|
||||
position: {},
|
||||
}, items: [
|
||||
{
|
||||
key: "addColumnAbove",
|
||||
type: "menuitem",
|
||||
title: "Add column left",
|
||||
onClick: function () { return editor.chain().focus().addColumnBefore().run(); },
|
||||
icon: "insertColumnLeft",
|
||||
},
|
||||
{
|
||||
key: "moveColumnLeft",
|
||||
type: "menuitem",
|
||||
title: "Move column left",
|
||||
onClick: function () { return moveColumnLeft(editor); },
|
||||
icon: "moveColumnLeft",
|
||||
},
|
||||
{
|
||||
key: "moveColumnRight",
|
||||
type: "menuitem",
|
||||
title: "Move column right",
|
||||
onClick: function () { return moveColumnRight(editor); },
|
||||
icon: "moveColumnRight",
|
||||
},
|
||||
{
|
||||
key: "deleteColumn",
|
||||
type: "menuitem",
|
||||
title: "Delete column",
|
||||
onClick: function () { return editor.chain().focus().deleteColumn().run(); },
|
||||
icon: "deleteColumn",
|
||||
},
|
||||
{
|
||||
key: "sortDesc",
|
||||
type: "menuitem",
|
||||
title: "Sort descending",
|
||||
onClick: function () { },
|
||||
icon: "sortDesc",
|
||||
},
|
||||
{
|
||||
key: "cellProperties",
|
||||
type: "menuitem",
|
||||
title: "Cell properties",
|
||||
onClick: function () {
|
||||
setShowCellProps(true);
|
||||
setMenuPosition({
|
||||
target: position.target || undefined,
|
||||
isTargetAbsolute: true,
|
||||
yOffset: 10,
|
||||
location: "below",
|
||||
});
|
||||
},
|
||||
icon: "cellProperties",
|
||||
},
|
||||
] }), _jsx(MenuPresenter, __assign({ isOpen: showCellProps, onClose: function () {
|
||||
setShowCellProps(false);
|
||||
editor.commands.focus();
|
||||
}, options: {
|
||||
type: "menu",
|
||||
position: menuPosition || {},
|
||||
}, items: [] }, { children: _jsx(CellProperties, { editor: editor, onClose: function () { return setShowCellProps(false); } }) }))] })));
|
||||
}
|
||||
function CellProperties(props) {
|
||||
var editor = props.editor, onClose = props.onClose;
|
||||
var attributes = editor.getAttributes("tableCell");
|
||||
console.log(attributes);
|
||||
return (_jsx(Popup, __assign({ title: "Cell properties", action: {
|
||||
icon: "close",
|
||||
iconColor: "error",
|
||||
onClick: onClose,
|
||||
} }, { children: _jsxs(Flex, __assign({ sx: { flexDirection: "column", width: 200, px: 1, mb: 2 } }, { children: [_jsx(ColorPickerTool, { color: attributes.backgroundColor, title: "Background color", icon: "backgroundColor", onColorChange: function (color) {
|
||||
return editor.commands.setCellAttribute("backgroundColor", color);
|
||||
} }), _jsx(ColorPickerTool, { color: attributes.color, title: "Text color", icon: "textColor", onColorChange: function (color) {
|
||||
return editor.commands.setCellAttribute("color", color);
|
||||
} }), _jsx(ColorPickerTool, { color: attributes.borderColor, title: "Border color", icon: "borderColor", onColorChange: function (color) {
|
||||
return editor.commands.setCellAttribute("borderColor", color);
|
||||
} }), _jsxs(Flex, __assign({ sx: { flexDirection: "column" } }, { children: [_jsxs(Flex, __assign({ sx: {
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
mt: 1,
|
||||
} }, { children: [_jsx(Text, __assign({ variant: "body" }, { children: "Border width" })), _jsxs(Text, __assign({ variant: "body" }, { children: [attributes.borderWidth || 1, "px"] }))] })), _jsx(Slider, { min: 1, max: 5, value: attributes.borderWidth || 1, onChange: function (e) {
|
||||
editor.commands.setCellAttribute("borderWidth", e.target.valueAsNumber);
|
||||
} })] }))] })) })));
|
||||
}
|
||||
function ColorPickerTool(props) {
|
||||
var color = props.color, title = props.title, icon = props.icon, onColorChange = props.onColorChange;
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var buttonRef = useRef(null);
|
||||
return (_jsxs(_Fragment, { children: [_jsxs(Flex, __assign({ sx: { justifyContent: "space-between", alignItems: "center", mt: 1 } }, { children: [_jsx(Text, __assign({ variant: "body" }, { children: title })), _jsx(ToolButton, { buttonRef: buttonRef, toggled: isOpen, title: title, id: icon, icon: icon, iconSize: 16, sx: {
|
||||
p: "2.5px",
|
||||
borderRadius: "small",
|
||||
backgroundColor: color || "transparent",
|
||||
":hover": { bg: color, filter: "brightness(90%)" },
|
||||
}, onClick: function () { return setIsOpen(true); } })] })), _jsx(MenuPresenter, __assign({ isOpen: isOpen, onClose: function () { return setIsOpen(false); }, items: [], options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: buttonRef.current || undefined,
|
||||
location: "below",
|
||||
align: "center",
|
||||
isTargetAbsolute: true,
|
||||
yOffset: 5,
|
||||
},
|
||||
} }, { children: _jsx(Flex, __assign({ sx: {
|
||||
flexDirection: "column",
|
||||
bg: "background",
|
||||
boxShadow: "menu",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "default",
|
||||
p: 1,
|
||||
width: 160,
|
||||
} }, { children: _jsx(ColorPicker, { colors: DEFAULT_COLORS, color: color, onClear: function () { return onColorChange(); }, onChange: function (color) { return onColorChange(color); } }) })) }))] }));
|
||||
}
|
||||
/**
|
||||
* Done:
|
||||
* insertTable
|
||||
*
|
||||
* addRowBefore
|
||||
* addRowAfter
|
||||
* deleteRow
|
||||
*
|
||||
* addColumnBefore
|
||||
* addColumnAfter
|
||||
* deleteColumn
|
||||
*
|
||||
* setCellAttribute
|
||||
*
|
||||
* deleteTable
|
||||
*
|
||||
* mergeCells
|
||||
* splitCell
|
||||
* mergeOrSplit
|
||||
*
|
||||
* toggleHeaderColumn
|
||||
* toggleHeaderRow
|
||||
* toggleHeaderCell
|
||||
* fixTables
|
||||
* goToNextCell
|
||||
* goToPreviousCell
|
||||
*/
|
||||
function moveColumnRight(editor) {
|
||||
var tr = editor.state.tr;
|
||||
var rect = selectedRect(editor.state);
|
||||
if (rect.right === rect.map.width)
|
||||
return;
|
||||
var transaction = moveColumn(tr, rect, rect.left, rect.left + 1);
|
||||
if (!transaction)
|
||||
return;
|
||||
editor.view.dispatch(transaction);
|
||||
}
|
||||
function moveColumnLeft(editor) {
|
||||
var tr = editor.state.tr;
|
||||
var rect = selectedRect(editor.state);
|
||||
if (rect.left === 0)
|
||||
return;
|
||||
var transaction = moveColumn(tr, rect, rect.left, rect.left - 1);
|
||||
if (!transaction)
|
||||
return;
|
||||
editor.view.dispatch(transaction);
|
||||
}
|
||||
function moveRowDown(editor) {
|
||||
var tr = editor.state.tr;
|
||||
var rect = selectedRect(editor.state);
|
||||
if (rect.top + 1 === rect.map.height)
|
||||
return;
|
||||
var transaction = moveRow(tr, rect, rect.top, rect.top + 1);
|
||||
if (!transaction)
|
||||
return;
|
||||
editor.view.dispatch(transaction);
|
||||
}
|
||||
function moveRowUp(editor) {
|
||||
var tr = editor.state.tr;
|
||||
var rect = selectedRect(editor.state);
|
||||
if (rect.top === 0)
|
||||
return;
|
||||
var transaction = moveRow(tr, rect, rect.top, rect.top - 1);
|
||||
if (!transaction)
|
||||
return;
|
||||
editor.view.dispatch(transaction);
|
||||
}
|
||||
function moveColumn(tr, rect, from, to) {
|
||||
var fromCells = getColumnCells(rect, from);
|
||||
var toCells = getColumnCells(rect, to);
|
||||
return moveCells(tr, rect, fromCells, toCells);
|
||||
}
|
||||
function getColumnCells(_a, col) {
|
||||
var map = _a.map, table = _a.table;
|
||||
var cells = [];
|
||||
for (var row = 0; row < map.height;) {
|
||||
var index = row * map.width + col;
|
||||
if (index >= map.map.length)
|
||||
break;
|
||||
var pos = map.map[index];
|
||||
var cell = table.nodeAt(pos);
|
||||
if (!cell)
|
||||
continue;
|
||||
cells.push({ cell: cell, pos: pos });
|
||||
row += cell.attrs.rowspan;
|
||||
console.log(cell.textContent);
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
function moveRow(tr, rect, from, to) {
|
||||
var fromCells = getRowCells(rect, from);
|
||||
var toCells = getRowCells(rect, to);
|
||||
return moveCells(tr, rect, fromCells, toCells);
|
||||
}
|
||||
function getRowCells(_a, row) {
|
||||
var map = _a.map, table = _a.table;
|
||||
var cells = [];
|
||||
for (var col = 0, index = row * map.width; col < map.width; col++, index++) {
|
||||
if (index >= map.map.length)
|
||||
break;
|
||||
var pos = map.map[index];
|
||||
var cell = table.nodeAt(pos);
|
||||
if (!cell)
|
||||
continue;
|
||||
cells.push({ cell: cell, pos: pos });
|
||||
col += cell.attrs.colspan - 1;
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
function moveCells(tr, rect, fromCells, toCells) {
|
||||
if (fromCells.length !== toCells.length)
|
||||
return;
|
||||
var mapStart = tr.mapping.maps.length;
|
||||
for (var i = 0; i < toCells.length; ++i) {
|
||||
var fromCell = fromCells[i];
|
||||
var toCell = toCells[i];
|
||||
var fromStart = tr.mapping
|
||||
.slice(mapStart)
|
||||
.map(rect.tableStart + fromCell.pos);
|
||||
var fromEnd = fromStart + fromCell.cell.nodeSize;
|
||||
var fromSlice = tr.doc.slice(fromStart, fromEnd);
|
||||
var toStart = tr.mapping
|
||||
.slice(mapStart)
|
||||
.map(rect.tableStart + toCell.pos);
|
||||
var toEnd = toStart + toCell.cell.nodeSize;
|
||||
var toSlice = tr.doc.slice(toStart, toEnd);
|
||||
tr.replace(toStart, toEnd, fromSlice);
|
||||
fromStart = tr.mapping.slice(mapStart).map(rect.tableStart + fromCell.pos);
|
||||
fromEnd = fromStart + fromCell.cell.nodeSize;
|
||||
tr.replace(fromStart, fromEnd, toSlice);
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
4
packages/editor/dist/toolbar/floatingmenus/types.d.ts
vendored
Normal file
4
packages/editor/dist/toolbar/floatingmenus/types.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Editor } from "@tiptap/core";
|
||||
export declare type FloatingMenuProps = {
|
||||
editor: Editor;
|
||||
};
|
||||
1
packages/editor/dist/toolbar/floatingmenus/types.js
vendored
Normal file
1
packages/editor/dist/toolbar/floatingmenus/types.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
50
packages/editor/dist/toolbar/icons.d.ts
vendored
Normal file
50
packages/editor/dist/toolbar/icons.d.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
export declare const Icons: {
|
||||
bold: string;
|
||||
italic: string;
|
||||
underline: string;
|
||||
strikethrough: string;
|
||||
code: string;
|
||||
alignCenter: string;
|
||||
alignLeft: string;
|
||||
alignRight: string;
|
||||
alignJustify: string;
|
||||
subscript: string;
|
||||
superscript: string;
|
||||
horizontalRule: string;
|
||||
codeblock: string;
|
||||
blockquote: string;
|
||||
formatClear: string;
|
||||
ltr: string;
|
||||
rtl: string;
|
||||
numberedList: string;
|
||||
bulletList: string;
|
||||
highlight: string;
|
||||
textColor: string;
|
||||
link: string;
|
||||
image: string;
|
||||
chevronDown: string;
|
||||
colorClear: string;
|
||||
check: string;
|
||||
loading: string;
|
||||
more: string;
|
||||
upload: string;
|
||||
attachment: string;
|
||||
table: string;
|
||||
insertRowBelow: string;
|
||||
insertRowAbove: string;
|
||||
moveRowDown: string;
|
||||
moveRowUp: string;
|
||||
deleteRow: string;
|
||||
toggleHeaderRow: string;
|
||||
insertColumnRight: string;
|
||||
insertColumnLeft: string;
|
||||
moveColumnRight: string;
|
||||
moveColumnLeft: string;
|
||||
deleteColumn: string;
|
||||
cellProperties: string;
|
||||
backgroundColor: string;
|
||||
borderColor: string;
|
||||
close: string;
|
||||
sortDesc: string;
|
||||
};
|
||||
export declare type IconNames = keyof typeof Icons;
|
||||
50
packages/editor/dist/toolbar/icons.js
vendored
Normal file
50
packages/editor/dist/toolbar/icons.js
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import { mdiAttachment, mdiBorderHorizontal, mdiCheck, mdiChevronDown, mdiCodeBraces, mdiCodeTags, mdiDotsVertical, mdiFormatAlignCenter, mdiFormatAlignJustify, mdiFormatAlignLeft, mdiFormatAlignRight, mdiFormatBold, mdiFormatClear, mdiFormatColorHighlight, mdiFormatColorText, mdiFormatItalic, mdiFormatListBulleted, mdiFormatListNumbered, mdiFormatQuoteClose, mdiFormatStrikethrough, mdiFormatSubscript, mdiFormatSuperscript, mdiFormatTextdirectionLToR, mdiFormatTextdirectionRToL, mdiFormatUnderline, mdiImage, mdiInvertColorsOff, mdiLinkPlus, mdiLoading, mdiTable, mdiTableBorder, mdiTableRowPlusBefore, mdiTableRowRemove, mdiTableColumnPlusBefore, mdiTableColumnRemove, mdiUploadOutline, mdiPlus, mdiSquareRoundedBadgeOutline, mdiFormatColorFill, mdiBorderAllVariant, mdiClose, mdiSortDescending, mdiArrowExpandRight, mdiArrowExpandLeft, mdiArrowExpandDown, mdiArrowExpandUp, } from "@mdi/js";
|
||||
export var Icons = {
|
||||
bold: mdiFormatBold,
|
||||
italic: mdiFormatItalic,
|
||||
underline: mdiFormatUnderline,
|
||||
strikethrough: mdiFormatStrikethrough,
|
||||
code: mdiCodeTags,
|
||||
alignCenter: mdiFormatAlignCenter,
|
||||
alignLeft: mdiFormatAlignLeft,
|
||||
alignRight: mdiFormatAlignRight,
|
||||
alignJustify: mdiFormatAlignJustify,
|
||||
subscript: mdiFormatSubscript,
|
||||
superscript: mdiFormatSuperscript,
|
||||
horizontalRule: mdiBorderHorizontal,
|
||||
codeblock: mdiCodeBraces,
|
||||
blockquote: mdiFormatQuoteClose,
|
||||
formatClear: mdiFormatClear,
|
||||
ltr: mdiFormatTextdirectionLToR,
|
||||
rtl: mdiFormatTextdirectionRToL,
|
||||
numberedList: mdiFormatListNumbered,
|
||||
bulletList: mdiFormatListBulleted,
|
||||
highlight: mdiFormatColorHighlight,
|
||||
textColor: mdiFormatColorText,
|
||||
link: mdiLinkPlus,
|
||||
image: mdiImage,
|
||||
chevronDown: mdiChevronDown,
|
||||
colorClear: mdiInvertColorsOff,
|
||||
check: mdiCheck,
|
||||
loading: mdiLoading,
|
||||
more: mdiDotsVertical,
|
||||
upload: mdiUploadOutline,
|
||||
attachment: mdiAttachment,
|
||||
table: mdiTable,
|
||||
insertRowBelow: mdiPlus,
|
||||
insertRowAbove: mdiTableRowPlusBefore,
|
||||
moveRowDown: mdiArrowExpandDown,
|
||||
moveRowUp: mdiArrowExpandUp,
|
||||
deleteRow: mdiTableRowRemove,
|
||||
toggleHeaderRow: mdiTableBorder,
|
||||
insertColumnRight: mdiPlus,
|
||||
insertColumnLeft: mdiTableColumnPlusBefore,
|
||||
moveColumnRight: mdiArrowExpandRight,
|
||||
moveColumnLeft: mdiArrowExpandLeft,
|
||||
deleteColumn: mdiTableColumnRemove,
|
||||
cellProperties: mdiSquareRoundedBadgeOutline,
|
||||
backgroundColor: mdiFormatColorFill,
|
||||
borderColor: mdiBorderAllVariant,
|
||||
close: mdiClose,
|
||||
sortDesc: mdiSortDescending,
|
||||
};
|
||||
2
packages/editor/dist/toolbar/index.d.ts
vendored
Normal file
2
packages/editor/dist/toolbar/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { Toolbar } from "./toolbar";
|
||||
export default Toolbar;
|
||||
2
packages/editor/dist/toolbar/index.js
vendored
Normal file
2
packages/editor/dist/toolbar/index.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { Toolbar } from "./toolbar";
|
||||
export default Toolbar;
|
||||
3
packages/editor/dist/toolbar/menus/index.d.ts
vendored
Normal file
3
packages/editor/dist/toolbar/menus/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="react" />
|
||||
import { FloatingMenuProps } from "./types";
|
||||
export declare function EditorFloatingMenus(props: FloatingMenuProps): JSX.Element;
|
||||
16
packages/editor/dist/toolbar/menus/index.js
vendored
Normal file
16
packages/editor/dist/toolbar/menus/index.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { TableRowFloatingMenu } from "./table";
|
||||
export function EditorFloatingMenus(props) {
|
||||
return (_jsx(_Fragment, { children: _jsx(TableRowFloatingMenu, __assign({}, props)) }));
|
||||
}
|
||||
3
packages/editor/dist/toolbar/menus/table.d.ts
vendored
Normal file
3
packages/editor/dist/toolbar/menus/table.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/// <reference types="react" />
|
||||
import { FloatingMenuProps } from "./types";
|
||||
export declare function TableRowFloatingMenu(props: FloatingMenuProps): JSX.Element;
|
||||
21
packages/editor/dist/toolbar/menus/table.js
vendored
Normal file
21
packages/editor/dist/toolbar/menus/table.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { FloatingMenu } from "@tiptap/react";
|
||||
import { Flex, Text } from "rebass";
|
||||
export function TableRowFloatingMenu(props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(FloatingMenu, __assign({ editor: editor, shouldShow: function (_a) {
|
||||
var editor = _a.editor, state = _a.state;
|
||||
return editor.isActive("tableRow") && state.selection.empty;
|
||||
} }, { children: _jsx(Flex, __assign({ sx: { bg: "background" } }, { children: _jsx(Text, { children: "Hello" }) })) })));
|
||||
}
|
||||
4
packages/editor/dist/toolbar/menus/types.d.ts
vendored
Normal file
4
packages/editor/dist/toolbar/menus/types.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Editor } from "@tiptap/core";
|
||||
export declare type FloatingMenuProps = {
|
||||
editor: Editor;
|
||||
};
|
||||
1
packages/editor/dist/toolbar/menus/types.js
vendored
Normal file
1
packages/editor/dist/toolbar/menus/types.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
8
packages/editor/dist/toolbar/toolbar.d.ts
vendored
Normal file
8
packages/editor/dist/toolbar/toolbar.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/// <reference types="react" />
|
||||
import { ThemeConfig } from "@notesnook/theme/dist/theme/types";
|
||||
import { Editor } from "@tiptap/core";
|
||||
declare type ToolbarProps = ThemeConfig & {
|
||||
editor: Editor | null;
|
||||
};
|
||||
export declare function Toolbar(props: ToolbarProps): JSX.Element | null;
|
||||
export {};
|
||||
45
packages/editor/dist/toolbar/toolbar.js
vendored
Normal file
45
packages/editor/dist/toolbar/toolbar.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { useTheme } from "@notesnook/theme";
|
||||
import { Flex } from "rebass";
|
||||
import { findToolById } from "./tools";
|
||||
import { ThemeProvider } from "emotion-theming";
|
||||
import { EditorFloatingMenus } from "./floating-menus";
|
||||
export function Toolbar(props) {
|
||||
var editor = props.editor, theme = props.theme, accent = props.accent, scale = props.scale;
|
||||
var themeProperties = useTheme({ accent: accent, theme: theme, scale: scale });
|
||||
var tools = [
|
||||
["bold", "italic", "underline", "strikethrough", "code"],
|
||||
["fontSize", "fontFamily", "headings"],
|
||||
["alignLeft", "alignCenter", "alignRight", "alignJustify"],
|
||||
["subscript", "superscript", "horizontalRule"],
|
||||
["codeblock", "blockquote"],
|
||||
["formatClear", "ltr", "rtl"],
|
||||
["numberedList", "bulletList"],
|
||||
["link", "image", "attachment", "table"],
|
||||
["textColor", "highlight"],
|
||||
];
|
||||
if (!editor)
|
||||
return null;
|
||||
return (_jsxs(ThemeProvider, __assign({ theme: themeProperties }, { children: [_jsx(Flex, __assign({ sx: { flexWrap: "wrap" } }, { children: tools.map(function (tools) {
|
||||
return (_jsx(Flex, __assign({ className: "toolbar-group", sx: {
|
||||
pr: 2,
|
||||
mr: 2,
|
||||
borderRight: "1px solid var(--border)",
|
||||
":last-of-type": { mr: 0, pr: 0, borderRight: "none" },
|
||||
} }, { children: tools.map(function (toolId) {
|
||||
var Component = findToolById(toolId).render;
|
||||
return _jsx(Component, { editor: editor });
|
||||
}) })));
|
||||
}) })), _jsx(EditorFloatingMenus, { editor: editor })] })));
|
||||
}
|
||||
25
packages/editor/dist/toolbar/tools/alignment.d.ts
vendored
Normal file
25
packages/editor/dist/toolbar/tools/alignment.d.ts
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
declare class AlignmentTool<TId extends ToolId, TTitle extends string> implements ITool {
|
||||
readonly id: TId;
|
||||
readonly title: TTitle;
|
||||
private readonly alignment;
|
||||
private readonly icon;
|
||||
constructor(id: TId, title: TTitle, alignment: "left" | "right" | "center" | "justify", icon: IconNames);
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class AlignCenter extends AlignmentTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export declare class AlignRight extends AlignmentTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export declare class AlignLeft extends AlignmentTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export declare class AlignJustify extends AlignmentTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export {};
|
||||
65
packages/editor/dist/toolbar/tools/alignment.js
vendored
Normal file
65
packages/editor/dist/toolbar/tools/alignment.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
var AlignmentTool = /** @class */ (function () {
|
||||
function AlignmentTool(id, title, alignment, icon) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.alignment = alignment;
|
||||
this.icon = icon;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(ToolButton, { title: _this.title, id: _this.id, icon: _this.icon, onClick: function () {
|
||||
return editor.chain().focus().setTextAlign(_this.alignment).run();
|
||||
}, toggled: editor.isActive({ textAlign: _this.alignment }) }));
|
||||
};
|
||||
}
|
||||
return AlignmentTool;
|
||||
}());
|
||||
var AlignCenter = /** @class */ (function (_super) {
|
||||
__extends(AlignCenter, _super);
|
||||
function AlignCenter() {
|
||||
return _super.call(this, "alignCenter", "Align center", "center", "alignCenter") || this;
|
||||
}
|
||||
return AlignCenter;
|
||||
}(AlignmentTool));
|
||||
export { AlignCenter };
|
||||
var AlignRight = /** @class */ (function (_super) {
|
||||
__extends(AlignRight, _super);
|
||||
function AlignRight() {
|
||||
return _super.call(this, "alignRight", "Align right", "right", "alignRight") || this;
|
||||
}
|
||||
return AlignRight;
|
||||
}(AlignmentTool));
|
||||
export { AlignRight };
|
||||
var AlignLeft = /** @class */ (function (_super) {
|
||||
__extends(AlignLeft, _super);
|
||||
function AlignLeft() {
|
||||
return _super.call(this, "alignLeft", "Align left", "left", "alignLeft") || this;
|
||||
}
|
||||
return AlignLeft;
|
||||
}(AlignmentTool));
|
||||
export { AlignLeft };
|
||||
var AlignJustify = /** @class */ (function (_super) {
|
||||
__extends(AlignJustify, _super);
|
||||
function AlignJustify() {
|
||||
return _super.call(this, "alignJustify", "Justify", "justify", "alignJustify") || this;
|
||||
}
|
||||
return AlignJustify;
|
||||
}(AlignmentTool));
|
||||
export { AlignJustify };
|
||||
42
packages/editor/dist/toolbar/tools/block.d.ts
vendored
Normal file
42
packages/editor/dist/toolbar/tools/block.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
declare class BlockTool<TId extends ToolId> implements ITool {
|
||||
readonly id: TId;
|
||||
readonly title: string;
|
||||
private readonly icon;
|
||||
private readonly command;
|
||||
constructor(id: TId, title: string, icon: IconNames, command: (editor: Editor) => boolean);
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class HorizontalRule extends BlockTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class CodeBlock extends BlockTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Blockquote extends BlockTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Image implements ITool {
|
||||
id: ToolId;
|
||||
title: string;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class Attachment extends BlockTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Table implements ITool {
|
||||
id: ToolId;
|
||||
title: string;
|
||||
private MAX_COLUMNS;
|
||||
private MAX_ROWS;
|
||||
private MIN_COLUMNS;
|
||||
private MIN_ROWS;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
private getCellLocation;
|
||||
private isCellHighlighted;
|
||||
}
|
||||
export {};
|
||||
220
packages/editor/dist/toolbar/tools/block.js
vendored
Normal file
220
packages/editor/dist/toolbar/tools/block.js
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
import { Icons } from "../icons";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Dropdown } from "../components/dropdown";
|
||||
import { Icon } from "../components/icon";
|
||||
import { Box, Button, Flex, Text } from "rebass";
|
||||
import { Popup } from "../components/popup";
|
||||
var BlockTool = /** @class */ (function () {
|
||||
function BlockTool(id, title, icon, command) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.command = command;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(ToolButton, { id: _this.id, title: _this.title, icon: _this.icon, onClick: function () { return _this.command(editor); }, toggled: editor.isActive(_this.id) }));
|
||||
};
|
||||
}
|
||||
return BlockTool;
|
||||
}());
|
||||
var HorizontalRule = /** @class */ (function (_super) {
|
||||
__extends(HorizontalRule, _super);
|
||||
function HorizontalRule() {
|
||||
return _super.call(this, "horizontalRule", "Horizontal rule", "horizontalRule", function (editor) {
|
||||
return editor.chain().focus().setHorizontalRule().run();
|
||||
}) || this;
|
||||
}
|
||||
return HorizontalRule;
|
||||
}(BlockTool));
|
||||
export { HorizontalRule };
|
||||
var CodeBlock = /** @class */ (function (_super) {
|
||||
__extends(CodeBlock, _super);
|
||||
function CodeBlock() {
|
||||
return _super.call(this, "codeblock", "Codeblock", "codeblock", function (editor) {
|
||||
return editor.chain().focus().toggleCodeBlock().run();
|
||||
}) || this;
|
||||
}
|
||||
return CodeBlock;
|
||||
}(BlockTool));
|
||||
export { CodeBlock };
|
||||
var Blockquote = /** @class */ (function (_super) {
|
||||
__extends(Blockquote, _super);
|
||||
function Blockquote() {
|
||||
return _super.call(this, "blockquote", "Blockquote", "blockquote", function (editor) {
|
||||
return editor.chain().focus().toggleBlockquote().run();
|
||||
}) || this;
|
||||
}
|
||||
return Blockquote;
|
||||
}(BlockTool));
|
||||
export { Blockquote };
|
||||
var Image = /** @class */ (function () {
|
||||
function Image() {
|
||||
this.id = "image";
|
||||
this.title = "Image";
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(_Fragment, { children: _jsx(Dropdown, { selectedItem: _jsx(Icon, { path: Icons.image, size: 16 }), items: [
|
||||
{
|
||||
key: "upload-from-disk",
|
||||
type: "menuitem",
|
||||
title: "Upload from disk",
|
||||
icon: "upload",
|
||||
onClick: function () { },
|
||||
},
|
||||
{
|
||||
key: "upload-from-url",
|
||||
type: "menuitem",
|
||||
title: "Attach from URL",
|
||||
icon: "link",
|
||||
onClick: function () { },
|
||||
},
|
||||
] }) }));
|
||||
};
|
||||
}
|
||||
return Image;
|
||||
}());
|
||||
export { Image };
|
||||
var Attachment = /** @class */ (function (_super) {
|
||||
__extends(Attachment, _super);
|
||||
function Attachment() {
|
||||
return _super.call(this, "attachment", "Attachment", "attachment", function (editor) {
|
||||
return false;
|
||||
}) || this;
|
||||
}
|
||||
return Attachment;
|
||||
}(BlockTool));
|
||||
export { Attachment };
|
||||
var Table = /** @class */ (function () {
|
||||
function Table() {
|
||||
var _this = this;
|
||||
this.id = "table";
|
||||
this.title = "Table";
|
||||
this.MAX_COLUMNS = 20;
|
||||
this.MAX_ROWS = 20;
|
||||
this.MIN_COLUMNS = 4;
|
||||
this.MIN_ROWS = 4;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var ref = useRef(null);
|
||||
var _b = useState({
|
||||
column: 0,
|
||||
row: 0,
|
||||
}), cellLocation = _b[0], setCellLocation = _b[1];
|
||||
var _c = useState({
|
||||
columns: _this.MIN_COLUMNS,
|
||||
rows: _this.MIN_ROWS,
|
||||
}), tableSize = _c[0], setTableSize = _c[1];
|
||||
useEffect(function () {
|
||||
setTableSize(function (old) {
|
||||
var columns = old.columns, rows = old.rows;
|
||||
var column = cellLocation.column, row = cellLocation.row;
|
||||
var isDecrease = row === rows - 2 || column === columns - 2;
|
||||
var rowFactor = Number(row === rows || row === rows - 2);
|
||||
var columnFactor = Number(column === columns || column === columns - 2);
|
||||
return {
|
||||
columns: isDecrease
|
||||
? Math.max(column + columnFactor, _this.MIN_COLUMNS)
|
||||
: Math.min(old.columns + columnFactor, _this.MAX_COLUMNS),
|
||||
rows: isDecrease
|
||||
? Math.max(row + rowFactor, _this.MIN_ROWS)
|
||||
: Math.min(old.rows + rowFactor, _this.MAX_ROWS),
|
||||
};
|
||||
});
|
||||
}, [cellLocation]);
|
||||
return (_jsxs(Flex, __assign({ ref: ref }, { children: [_jsxs(Button, __assign({ sx: {
|
||||
p: 1,
|
||||
m: 0,
|
||||
bg: isOpen ? "hover" : "transparent",
|
||||
mr: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
":hover": { bg: "hover" },
|
||||
":last-of-type": {
|
||||
mr: 0,
|
||||
},
|
||||
}, onClick: function () { return setIsOpen(function (s) { return !s; }); } }, { children: [_jsx(Icon, { path: Icons.table, color: "text", size: 18 }), _jsx(Icon, { path: Icons.chevronDown, color: "text", size: 18 })] })), _jsx(MenuPresenter, __assign({ isOpen: isOpen, onClose: function () { return setIsOpen(false); }, items: [], options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: ref.current || undefined,
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
yOffset: 5,
|
||||
},
|
||||
} }, { children: _jsx(Popup, { children: _jsxs(Flex, __assign({ sx: { p: 1, flexDirection: "column", alignItems: "center" } }, { children: [_jsx(Box, __assign({ sx: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr ".repeat(tableSize.columns),
|
||||
gap: "3px",
|
||||
bg: "background",
|
||||
} }, { children: Array(tableSize.columns * tableSize.rows)
|
||||
.fill(0)
|
||||
.map(function (_, index) { return (_jsx(Box, { width: 15, height: 15, sx: {
|
||||
border: "1px solid var(--disabled)",
|
||||
borderRadius: "2px",
|
||||
bg: _this.isCellHighlighted(index, cellLocation, tableSize)
|
||||
? "disabled"
|
||||
: "transparent",
|
||||
":hover": {
|
||||
bg: "disabled",
|
||||
},
|
||||
}, onMouseEnter: function () {
|
||||
setCellLocation(_this.getCellLocation(index, tableSize));
|
||||
}, onClick: function () {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.insertTable({
|
||||
cols: cellLocation.column,
|
||||
rows: cellLocation.row,
|
||||
})
|
||||
.run();
|
||||
setIsOpen(false);
|
||||
} })); }) })), _jsxs(Text, __assign({ variant: "body", sx: { mt: 1 } }, { children: [cellLocation.column, "x", cellLocation.row] }))] })) }) }))] })));
|
||||
};
|
||||
}
|
||||
Table.prototype.getCellLocation = function (index, tableSize) {
|
||||
var cellIndex = index + 1;
|
||||
var column = cellIndex % tableSize.columns;
|
||||
var row = cellIndex / tableSize.columns;
|
||||
var flooredRow = Math.floor(row);
|
||||
row = row === flooredRow ? row : flooredRow + 1;
|
||||
return { column: column ? column : tableSize.columns, row: row };
|
||||
};
|
||||
Table.prototype.isCellHighlighted = function (index, currentCellLocation, tableSize) {
|
||||
var cellLocation = this.getCellLocation(index, tableSize);
|
||||
return (cellLocation.row <= currentCellLocation.row &&
|
||||
cellLocation.column <= currentCellLocation.column);
|
||||
};
|
||||
return Table;
|
||||
}());
|
||||
export { Table };
|
||||
28
packages/editor/dist/toolbar/tools/colors.d.ts
vendored
Normal file
28
packages/editor/dist/toolbar/tools/colors.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
export declare const DEFAULT_COLORS: string[];
|
||||
declare class ColorTool implements ITool {
|
||||
readonly id: ToolId;
|
||||
readonly title: string;
|
||||
private readonly icon;
|
||||
private readonly onColorChange;
|
||||
constructor(id: ToolId, title: string, icon: IconNames, onColorChange: (editor: Editor, color?: string) => void);
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class Highlight extends ColorTool {
|
||||
constructor();
|
||||
}
|
||||
export declare class TextColor extends ColorTool {
|
||||
constructor();
|
||||
}
|
||||
declare type ColorPickerProps = {
|
||||
colors: string[];
|
||||
color: string;
|
||||
onClear: () => void;
|
||||
onChange: (color: string) => void;
|
||||
};
|
||||
export declare function ColorPicker(props: ColorPickerProps): JSX.Element;
|
||||
export {};
|
||||
182
packages/editor/dist/toolbar/tools/colors.js
vendored
Normal file
182
packages/editor/dist/toolbar/tools/colors.js
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { Box, Button, Flex, Text } from "rebass";
|
||||
import { Input } from "@rebass/forms";
|
||||
import { Icon } from "../components/icon";
|
||||
import { Icons } from "../icons";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { useRef, useState } from "react";
|
||||
import tinycolor from "tinycolor2";
|
||||
export var DEFAULT_COLORS = [
|
||||
"#f44336",
|
||||
"#e91e63",
|
||||
"#9c27b0",
|
||||
"#673ab7",
|
||||
"#3f51b5",
|
||||
"#2196f3",
|
||||
"#03a9f4",
|
||||
"#00bcd4",
|
||||
"#009688",
|
||||
"#4caf50",
|
||||
"#8bc34a",
|
||||
"#cddc39",
|
||||
"#ffeb3b",
|
||||
"#ffc107",
|
||||
];
|
||||
var ColorTool = /** @class */ (function () {
|
||||
function ColorTool(id, title, icon, onColorChange) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.onColorChange = onColorChange;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var attrs = editor.getAttributes(_this.id === "highlight" ? "highlight" : "textStyle");
|
||||
var ref = useRef(null);
|
||||
var isActive = editor.isActive(_this.id === "highlight" ? "highlight" : "textStyle", { color: /\W+/gm });
|
||||
return (_jsxs(Flex, __assign({ ref: ref }, { children: [_jsx(ToolButton, { title: _this.title, id: _this.id, icon: _this.icon, onClick: function () { }, toggled: false, sx: { mr: 0, bg: isActive ? attrs.color : "transparent" } }), _jsx(Button, __assign({ sx: {
|
||||
p: 0,
|
||||
m: 0,
|
||||
bg: "transparent",
|
||||
":hover": { bg: "hover" },
|
||||
":last-of-type": {
|
||||
mr: 0,
|
||||
},
|
||||
}, onClick: function () { return setIsOpen(function (s) { return !s; }); } }, { children: _jsx(Icon, { path: Icons.chevronDown, color: "text", size: 18 }) })), _jsx(MenuPresenter, __assign({ isOpen: isOpen, onClose: function () { return setIsOpen(false); }, items: [],
|
||||
// sx={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", p: 1 }}
|
||||
options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: ref.current || undefined,
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
align: "center",
|
||||
yOffset: 5,
|
||||
},
|
||||
} }, { children: _jsx(Flex, __assign({ sx: {
|
||||
flexDirection: "column",
|
||||
bg: "background",
|
||||
boxShadow: "menu",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "default",
|
||||
p: 1,
|
||||
width: 160,
|
||||
} }, { children: _jsx(ColorPicker, { colors: DEFAULT_COLORS, color: attrs.color, onClear: function () { return _this.onColorChange(editor); }, onChange: function (color) { return _this.onColorChange(editor, color); } }) })) }))] })));
|
||||
};
|
||||
}
|
||||
return ColorTool;
|
||||
}());
|
||||
var Highlight = /** @class */ (function (_super) {
|
||||
__extends(Highlight, _super);
|
||||
function Highlight() {
|
||||
return _super.call(this, "highlight", "Highlight", "highlight", function (editor, color) {
|
||||
return color
|
||||
? editor.chain().focus().toggleHighlight({ color: color }).run()
|
||||
: editor.chain().focus().unsetHighlight().run();
|
||||
}) || this;
|
||||
}
|
||||
return Highlight;
|
||||
}(ColorTool));
|
||||
export { Highlight };
|
||||
var TextColor = /** @class */ (function (_super) {
|
||||
__extends(TextColor, _super);
|
||||
function TextColor() {
|
||||
return _super.call(this, "textColor", "Text color", "textColor", function (editor, color) {
|
||||
return color
|
||||
? editor.chain().focus().setColor(color).run()
|
||||
: editor.chain().focus().unsetColor().run();
|
||||
}) || this;
|
||||
}
|
||||
return TextColor;
|
||||
}(ColorTool));
|
||||
export { TextColor };
|
||||
export function ColorPicker(props) {
|
||||
var colors = props.colors, color = props.color, onClear = props.onClear, onChange = props.onChange;
|
||||
var _a = useState(tinycolor(color || colors[0]).toHexString()), currentColor = _a[0], setCurrentColor = _a[1];
|
||||
return (_jsxs(_Fragment, { children: [_jsx(Flex, __assign({ sx: {
|
||||
width: "100%",
|
||||
height: 50,
|
||||
bg: currentColor,
|
||||
mb: 1,
|
||||
borderRadius: "default",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
} }, { children: _jsx(Text, __assign({ sx: {
|
||||
fontSize: "subheading",
|
||||
color: tinycolor(currentColor).isDark() ? "white" : "black",
|
||||
} }, { children: currentColor })) })), _jsxs(Box, __assign({ sx: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr",
|
||||
} }, { children: [colors.map(function (color) { return (_jsx(Box, { sx: {
|
||||
bg: color,
|
||||
width: 25,
|
||||
height: 25,
|
||||
m: "2px",
|
||||
borderRadius: "default",
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
filter: "brightness(85%)",
|
||||
},
|
||||
}, onClick: function () {
|
||||
setCurrentColor(color);
|
||||
onChange(color);
|
||||
} })); }), _jsx(Flex, __assign({ sx: {
|
||||
width: 25,
|
||||
height: 25,
|
||||
m: "2px",
|
||||
borderRadius: "default",
|
||||
cursor: "pointer",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
":hover": {
|
||||
filter: "brightness(85%)",
|
||||
},
|
||||
}, onClick: onClear }, { children: _jsx(Icon, { path: Icons.colorClear, size: 18 }) }))] })), _jsxs(Flex, __assign({ sx: {
|
||||
mt: 1,
|
||||
borderRadius: "default",
|
||||
} }, { children: [_jsx(Input, { placeholder: "#000000", sx: {
|
||||
p: 1,
|
||||
m: 0,
|
||||
fontSize: "body",
|
||||
border: "none",
|
||||
borderWidth: 0,
|
||||
}, value: currentColor, maxLength: 7, onChange: function (e) {
|
||||
var value = e.target.value;
|
||||
if (!value)
|
||||
return;
|
||||
setCurrentColor(value);
|
||||
} }), _jsx(Button, __assign({ sx: {
|
||||
bg: "transparent",
|
||||
p: 1,
|
||||
":hover": { bg: "hover" },
|
||||
cursor: "pointer",
|
||||
}, onClick: function () { return onChange(currentColor); } }, { children: _jsx(Icon, { path: Icons.check, color: "text", size: 18 }) }))] }))] }));
|
||||
}
|
||||
16
packages/editor/dist/toolbar/tools/font.d.ts
vendored
Normal file
16
packages/editor/dist/toolbar/tools/font.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { ToolId } from ".";
|
||||
export declare class FontSize implements ITool {
|
||||
title: string;
|
||||
id: ToolId;
|
||||
private defaultFontSizes;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class FontFamily implements ITool {
|
||||
title: string;
|
||||
id: ToolId;
|
||||
private fontFamilies;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
private toMenuItems;
|
||||
}
|
||||
69
packages/editor/dist/toolbar/tools/font.js
vendored
Normal file
69
packages/editor/dist/toolbar/tools/font.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { Dropdown } from "../components/dropdown";
|
||||
var FontSize = /** @class */ (function () {
|
||||
function FontSize() {
|
||||
var _this = this;
|
||||
this.title = "Font size";
|
||||
this.id = "fontSize";
|
||||
this.defaultFontSizes = [
|
||||
12, 14, 16, 18, 20, 24, 28, 32, 36, 42, 48, 60, 72, 100,
|
||||
];
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var currentFontSize = _this.defaultFontSizes.find(function (size) {
|
||||
return editor.isActive("textStyle", { fontSize: "".concat(size, "px") });
|
||||
}) || 16;
|
||||
return (_jsx(Dropdown, { selectedItem: "".concat(currentFontSize, "px"), items: _this.defaultFontSizes.map(function (size) { return ({
|
||||
key: "".concat(size, "px"),
|
||||
type: "menuitem",
|
||||
title: "".concat(size, "px"),
|
||||
isChecked: size === currentFontSize,
|
||||
onClick: function () { return editor.chain().focus().setFontSize("".concat(size, "px")).run(); },
|
||||
}); }) }));
|
||||
};
|
||||
}
|
||||
return FontSize;
|
||||
}());
|
||||
export { FontSize };
|
||||
var FontFamily = /** @class */ (function () {
|
||||
function FontFamily() {
|
||||
var _this = this;
|
||||
this.title = "Font family";
|
||||
this.id = "fontFamily";
|
||||
this.fontFamilies = {
|
||||
System: "Open Sans",
|
||||
Serif: "serif",
|
||||
Monospace: "monospace",
|
||||
};
|
||||
this.render = function (props) {
|
||||
var _a, _b;
|
||||
var editor = props.editor;
|
||||
var currentFontFamily = ((_b = (_a = Object.entries(_this.fontFamilies)
|
||||
.find(function (_a) {
|
||||
var key = _a[0], value = _a[1];
|
||||
return editor.isActive("textStyle", { fontFamily: value });
|
||||
})) === null || _a === void 0 ? void 0 : _a.map(function (a) { return a; })) === null || _b === void 0 ? void 0 : _b.at(0)) || "System";
|
||||
return (_jsx(Dropdown, { selectedItem: currentFontFamily, items: _this.toMenuItems(editor, currentFontFamily) }));
|
||||
};
|
||||
}
|
||||
FontFamily.prototype.toMenuItems = function (editor, currentFontFamily) {
|
||||
var menuItems = [];
|
||||
var _loop_1 = function (key) {
|
||||
var value = this_1.fontFamilies[key];
|
||||
menuItems.push({
|
||||
key: key,
|
||||
type: "menuitem",
|
||||
title: key,
|
||||
isChecked: key === currentFontFamily,
|
||||
onClick: function () { return editor.chain().focus().setFontFamily(value).run(); },
|
||||
});
|
||||
};
|
||||
var this_1 = this;
|
||||
for (var key in this.fontFamilies) {
|
||||
_loop_1(key);
|
||||
}
|
||||
return menuItems;
|
||||
};
|
||||
return FontFamily;
|
||||
}());
|
||||
export { FontFamily };
|
||||
10
packages/editor/dist/toolbar/tools/headings.d.ts
vendored
Normal file
10
packages/editor/dist/toolbar/tools/headings.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { ToolId } from ".";
|
||||
export declare class Headings implements ITool {
|
||||
title: string;
|
||||
id: ToolId;
|
||||
private defaultLevels;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
private toMenuItems;
|
||||
}
|
||||
51
packages/editor/dist/toolbar/tools/headings.js
vendored
Normal file
51
packages/editor/dist/toolbar/tools/headings.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || Array.prototype.slice.call(from));
|
||||
};
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { Dropdown } from "../components/dropdown";
|
||||
var Headings = /** @class */ (function () {
|
||||
function Headings() {
|
||||
var _this = this;
|
||||
this.title = "Headings";
|
||||
this.id = "headings";
|
||||
this.defaultLevels = [1, 2, 3, 4, 5, 6];
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var currentHeadingLevel = _this.defaultLevels.find(function (level) {
|
||||
return editor.isActive("heading", { level: level });
|
||||
});
|
||||
return (_jsx(Dropdown, { selectedItem: currentHeadingLevel ? "Heading ".concat(currentHeadingLevel) : "Paragraph", items: _this.toMenuItems(editor, currentHeadingLevel) }));
|
||||
};
|
||||
}
|
||||
Headings.prototype.toMenuItems = function (editor, currentHeadingLevel) {
|
||||
var menuItems = this.defaultLevels.map(function (level) { return ({
|
||||
type: "menuitem",
|
||||
key: "heading-".concat(level),
|
||||
title: "Heading ".concat(level),
|
||||
isChecked: level === currentHeadingLevel,
|
||||
onClick: function () {
|
||||
return editor
|
||||
.chain()
|
||||
.focus()
|
||||
.setHeading({ level: level })
|
||||
.run();
|
||||
},
|
||||
}); });
|
||||
var paragraph = {
|
||||
key: "paragraph",
|
||||
type: "menuitem",
|
||||
title: "Paragraph",
|
||||
isChecked: !currentHeadingLevel,
|
||||
onClick: function () { return editor.chain().focus().setParagraph().run(); },
|
||||
};
|
||||
return __spreadArray([paragraph], menuItems, true);
|
||||
};
|
||||
return Headings;
|
||||
}());
|
||||
export { Headings };
|
||||
42
packages/editor/dist/toolbar/tools/index.d.ts
vendored
Normal file
42
packages/editor/dist/toolbar/tools/index.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ITool } from "../types";
|
||||
import { Bold, Italic, Underline, Strikethrough, Code, Subscript, Superscript, ClearFormatting, Link } from "./inline";
|
||||
import { FontSize, FontFamily } from "./font";
|
||||
import { AlignCenter, AlignLeft, AlignRight, AlignJustify } from "./alignment";
|
||||
import { Blockquote, CodeBlock, HorizontalRule, Image, Attachment, Table } from "./block";
|
||||
import { Headings } from "./headings";
|
||||
import { NumberedList, BulletList } from "./lists";
|
||||
import { LeftToRight, RightToLeft } from "./text-direction";
|
||||
import { Highlight, TextColor } from "./colors";
|
||||
declare const tools: {
|
||||
bold: Bold;
|
||||
italic: Italic;
|
||||
underline: Underline;
|
||||
strikethrough: Strikethrough;
|
||||
code: Code;
|
||||
formatClear: ClearFormatting;
|
||||
alignCenter: AlignCenter;
|
||||
alignRight: AlignRight;
|
||||
alignLeft: AlignLeft;
|
||||
alignJustify: AlignJustify;
|
||||
subscript: Subscript;
|
||||
superscript: Superscript;
|
||||
fontSize: FontSize;
|
||||
fontFamily: FontFamily;
|
||||
horizontalRule: HorizontalRule;
|
||||
codeblock: CodeBlock;
|
||||
blockquote: Blockquote;
|
||||
headings: Headings;
|
||||
ltr: LeftToRight;
|
||||
rtl: RightToLeft;
|
||||
numberedList: NumberedList;
|
||||
bulletList: BulletList;
|
||||
textColor: TextColor;
|
||||
highlight: Highlight;
|
||||
link: Link;
|
||||
image: Image;
|
||||
attachment: Attachment;
|
||||
table: Table;
|
||||
};
|
||||
export declare type ToolId = keyof typeof tools;
|
||||
export declare function findToolById(id: ToolId): ITool;
|
||||
export {};
|
||||
41
packages/editor/dist/toolbar/tools/index.js
vendored
Normal file
41
packages/editor/dist/toolbar/tools/index.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Bold, Italic, Underline, Strikethrough, Code, Subscript, Superscript, ClearFormatting, Link, } from "./inline";
|
||||
import { FontSize, FontFamily } from "./font";
|
||||
import { AlignCenter, AlignLeft, AlignRight, AlignJustify } from "./alignment";
|
||||
import { Blockquote, CodeBlock, HorizontalRule, Image, Attachment, Table, } from "./block";
|
||||
import { Headings } from "./headings";
|
||||
import { NumberedList, BulletList } from "./lists";
|
||||
import { LeftToRight, RightToLeft } from "./text-direction";
|
||||
import { Highlight, TextColor } from "./colors";
|
||||
var tools = {
|
||||
bold: new Bold(),
|
||||
italic: new Italic(),
|
||||
underline: new Underline(),
|
||||
strikethrough: new Strikethrough(),
|
||||
code: new Code(),
|
||||
formatClear: new ClearFormatting(),
|
||||
alignCenter: new AlignCenter(),
|
||||
alignRight: new AlignRight(),
|
||||
alignLeft: new AlignLeft(),
|
||||
alignJustify: new AlignJustify(),
|
||||
subscript: new Subscript(),
|
||||
superscript: new Superscript(),
|
||||
fontSize: new FontSize(),
|
||||
fontFamily: new FontFamily(),
|
||||
horizontalRule: new HorizontalRule(),
|
||||
codeblock: new CodeBlock(),
|
||||
blockquote: new Blockquote(),
|
||||
headings: new Headings(),
|
||||
ltr: new LeftToRight(),
|
||||
rtl: new RightToLeft(),
|
||||
numberedList: new NumberedList(),
|
||||
bulletList: new BulletList(),
|
||||
textColor: new TextColor(),
|
||||
highlight: new Highlight(),
|
||||
link: new Link(),
|
||||
image: new Image(),
|
||||
attachment: new Attachment(),
|
||||
table: new Table(),
|
||||
};
|
||||
export function findToolById(id) {
|
||||
return tools[id];
|
||||
}
|
||||
43
packages/editor/dist/toolbar/tools/inline.d.ts
vendored
Normal file
43
packages/editor/dist/toolbar/tools/inline.d.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
declare class InlineTool<TId extends ToolId> implements ITool {
|
||||
readonly id: TId;
|
||||
readonly title: string;
|
||||
private readonly icon;
|
||||
constructor(id: TId, title: string, icon: IconNames);
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class Italic extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Strikethrough extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Underline extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Code extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Bold extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Subscript extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class Superscript extends InlineTool<ToolId> {
|
||||
constructor();
|
||||
}
|
||||
export declare class ClearFormatting implements ITool {
|
||||
id: ToolId;
|
||||
title: string;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class Link implements ITool {
|
||||
id: ToolId;
|
||||
title: string;
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export {};
|
||||
176
packages/editor/dist/toolbar/tools/inline.js
vendored
Normal file
176
packages/editor/dist/toolbar/tools/inline.js
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { useRef, useState } from "react";
|
||||
import { Flex } from "rebass";
|
||||
import { Input } from "@rebass/forms";
|
||||
import { Popup } from "../components/popup";
|
||||
var InlineTool = /** @class */ (function () {
|
||||
function InlineTool(id, title, icon) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(ToolButton, { title: _this.title, id: _this.id, icon: _this.icon, onClick: function () { return editor.chain().focus().toggleMark(_this.id).run(); }, toggled: editor.isActive(_this.id) }));
|
||||
};
|
||||
}
|
||||
return InlineTool;
|
||||
}());
|
||||
var Italic = /** @class */ (function (_super) {
|
||||
__extends(Italic, _super);
|
||||
function Italic() {
|
||||
return _super.call(this, "italic", "Italic", "italic") || this;
|
||||
}
|
||||
return Italic;
|
||||
}(InlineTool));
|
||||
export { Italic };
|
||||
var Strikethrough = /** @class */ (function (_super) {
|
||||
__extends(Strikethrough, _super);
|
||||
function Strikethrough() {
|
||||
return _super.call(this, "strikethrough", "Strikethrough", "strikethrough") || this;
|
||||
}
|
||||
return Strikethrough;
|
||||
}(InlineTool));
|
||||
export { Strikethrough };
|
||||
var Underline = /** @class */ (function (_super) {
|
||||
__extends(Underline, _super);
|
||||
function Underline() {
|
||||
return _super.call(this, "underline", "Underline", "underline") || this;
|
||||
}
|
||||
return Underline;
|
||||
}(InlineTool));
|
||||
export { Underline };
|
||||
var Code = /** @class */ (function (_super) {
|
||||
__extends(Code, _super);
|
||||
function Code() {
|
||||
return _super.call(this, "code", "Code", "code") || this;
|
||||
}
|
||||
return Code;
|
||||
}(InlineTool));
|
||||
export { Code };
|
||||
var Bold = /** @class */ (function (_super) {
|
||||
__extends(Bold, _super);
|
||||
function Bold() {
|
||||
return _super.call(this, "bold", "Bold", "bold") || this;
|
||||
}
|
||||
return Bold;
|
||||
}(InlineTool));
|
||||
export { Bold };
|
||||
var Subscript = /** @class */ (function (_super) {
|
||||
__extends(Subscript, _super);
|
||||
function Subscript() {
|
||||
return _super.call(this, "subscript", "Subscript", "subscript") || this;
|
||||
}
|
||||
return Subscript;
|
||||
}(InlineTool));
|
||||
export { Subscript };
|
||||
var Superscript = /** @class */ (function (_super) {
|
||||
__extends(Superscript, _super);
|
||||
function Superscript() {
|
||||
return _super.call(this, "superscript", "Superscript", "superscript") || this;
|
||||
}
|
||||
return Superscript;
|
||||
}(InlineTool));
|
||||
export { Superscript };
|
||||
var ClearFormatting = /** @class */ (function () {
|
||||
function ClearFormatting() {
|
||||
var _this = this;
|
||||
this.id = "formatClear";
|
||||
this.title = "Clear all formatting";
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(ToolButton, { title: _this.title, id: _this.id, icon: "formatClear", onClick: function () {
|
||||
return editor.chain().focus().clearNodes().unsetAllMarks().run();
|
||||
}, toggled: false }));
|
||||
};
|
||||
}
|
||||
return ClearFormatting;
|
||||
}());
|
||||
export { ClearFormatting };
|
||||
var Link = /** @class */ (function () {
|
||||
function Link() {
|
||||
var _this = this;
|
||||
this.id = "link";
|
||||
this.title = "Link";
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var buttonRef = useRef(null);
|
||||
var targetRef = useRef();
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var _b = useState(), href = _b[0], setHref = _b[1];
|
||||
var _c = useState(), text = _c[0], setText = _c[1];
|
||||
var currentUrl = editor.getAttributes("link").href;
|
||||
var isEditing = !!currentUrl;
|
||||
return (_jsxs(_Fragment, { children: [_jsx(ToolButton, { ref: buttonRef, title: _this.title, id: _this.id, icon: "link", onClick: function () {
|
||||
if (isEditing)
|
||||
setHref(currentUrl);
|
||||
var _a = editor.state.selection, from = _a.from, to = _a.to, $from = _a.$from;
|
||||
var selectedNode = $from.node();
|
||||
var pos = selectedNode.isTextblock ? $from.before() : $from.pos;
|
||||
var domNode = editor.view.nodeDOM(pos);
|
||||
targetRef.current = domNode;
|
||||
var selectedText = isEditing
|
||||
? selectedNode.textContent
|
||||
: editor.state.doc.textBetween(from, to);
|
||||
setText(selectedText);
|
||||
setIsOpen(true);
|
||||
}, toggled: isOpen || !!isEditing }), _jsx(MenuPresenter, __assign({ options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: targetRef.current || buttonRef.current || undefined,
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
yOffset: 5,
|
||||
},
|
||||
}, isOpen: isOpen, items: [], onClose: function () {
|
||||
editor.commands.focus();
|
||||
setIsOpen(false);
|
||||
} }, { children: _jsx(Popup, __assign({ title: isEditing ? "Edit link" : "Insert link", action: {
|
||||
text: isEditing ? "Edit" : "Insert",
|
||||
onClick: function () {
|
||||
if (!href)
|
||||
return;
|
||||
var commandChain = editor
|
||||
.chain()
|
||||
.focus()
|
||||
.extendMarkRange("link")
|
||||
.setLink({ href: href, target: "_blank" });
|
||||
if (text)
|
||||
commandChain = commandChain.insertContent(text).focus();
|
||||
commandChain.run();
|
||||
setIsOpen(false);
|
||||
},
|
||||
} }, { children: _jsxs(Flex, __assign({ sx: { p: 1, width: 300, flexDirection: "column" } }, { children: [_jsx(Input, { type: "text", placeholder: "Link text", value: text, onChange: function (e) { return setText(e.target.value); } }), _jsx(Input, { type: "url", sx: { mt: 1 }, autoFocus: true, placeholder: "https://example.com/", value: href, onChange: function (e) { return setHref(e.target.value); } })] })) })) }))] }));
|
||||
};
|
||||
}
|
||||
return Link;
|
||||
}());
|
||||
export { Link };
|
||||
32
packages/editor/dist/toolbar/tools/lists.d.ts
vendored
Normal file
32
packages/editor/dist/toolbar/tools/lists.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
declare type ListSubType<TListStyleTypes> = {
|
||||
items: string[];
|
||||
title: string;
|
||||
type: TListStyleTypes;
|
||||
};
|
||||
declare type ListOptions<TListStyleTypes> = {
|
||||
icon: IconNames;
|
||||
type: "bulletList" | "orderedList";
|
||||
onClick: (editor: Editor) => void;
|
||||
subTypes: ListSubType<TListStyleTypes>[];
|
||||
};
|
||||
declare class ListTool<TListStyleTypes extends string> implements ITool {
|
||||
readonly id: ToolId;
|
||||
readonly title: string;
|
||||
private readonly options;
|
||||
constructor(id: ToolId, title: string, options: ListOptions<TListStyleTypes>);
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
declare type NumberedListStyleTypes = "lower-roman" | "upper-roman" | "lower-greek" | "lower-alpha" | "upper-alpha" | "decimal";
|
||||
export declare class NumberedList extends ListTool<NumberedListStyleTypes> {
|
||||
constructor();
|
||||
}
|
||||
declare type BulletListStyleTypes = "circle" | "square" | "disc";
|
||||
export declare class BulletList extends ListTool<BulletListStyleTypes> {
|
||||
constructor();
|
||||
}
|
||||
export {};
|
||||
151
packages/editor/dist/toolbar/tools/lists.js
vendored
Normal file
151
packages/editor/dist/toolbar/tools/lists.js
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
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);
|
||||
};
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
import { Box, Button, Flex } from "rebass";
|
||||
import { Icon } from "../components/icon";
|
||||
import { Icons } from "../icons";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { useRef, useState } from "react";
|
||||
var ListTool = /** @class */ (function () {
|
||||
function ListTool(id, title, options) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.options = options;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
var _a = useState(false), isOpen = _a[0], setIsOpen = _a[1];
|
||||
var ref = useRef(null);
|
||||
var isActive = editor.isActive(_this.options.type);
|
||||
return (_jsxs(Flex, __assign({ ref: ref }, { children: [_jsx(ToolButton, { title: _this.title, id: _this.id, icon: _this.options.icon, onClick: function () { return _this.options.onClick(editor); }, toggled: isActive, sx: { mr: 0 } }), _jsx(Button, __assign({ sx: {
|
||||
p: 0,
|
||||
m: 0,
|
||||
bg: "transparent",
|
||||
":hover": { bg: "hover" },
|
||||
":last-of-type": {
|
||||
mr: 0,
|
||||
},
|
||||
}, onClick: function () { return setIsOpen(function (s) { return !s; }); } }, { children: _jsx(Icon, { path: Icons.chevronDown, color: "text", size: 18 }) })), _jsx(MenuPresenter, { isOpen: isOpen, onClose: function () { return setIsOpen(false); }, items: _this.options.subTypes.map(function (item) { return ({
|
||||
key: item.type,
|
||||
tooltip: item.title,
|
||||
type: "menuitem",
|
||||
component: function () { return _jsx(ListThumbnail, { listStyleType: item.type }); },
|
||||
onClick: function () {
|
||||
var chain = editor.chain().focus();
|
||||
if (!isActive) {
|
||||
if (_this.options.type === "bulletList")
|
||||
chain = chain.toggleBulletList();
|
||||
else
|
||||
chain = chain.toggleOrderedList();
|
||||
}
|
||||
return chain
|
||||
.updateAttributes(_this.options.type, { listType: item.type })
|
||||
.run();
|
||||
},
|
||||
}); }), sx: { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", p: 1 }, options: {
|
||||
type: "menu",
|
||||
position: {
|
||||
target: ref.current || undefined,
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
yOffset: 5,
|
||||
},
|
||||
} })] })));
|
||||
};
|
||||
}
|
||||
return ListTool;
|
||||
}());
|
||||
var NumberedList = /** @class */ (function (_super) {
|
||||
__extends(NumberedList, _super);
|
||||
function NumberedList() {
|
||||
var options = {
|
||||
type: "orderedList",
|
||||
icon: "numberedList",
|
||||
onClick: function (editor) { return editor.chain().focus().toggleOrderedList().run(); },
|
||||
subTypes: [
|
||||
{ type: "decimal", title: "Decimal", items: ["1", "2", "3"] },
|
||||
{ type: "upper-alpha", title: "Upper alpha", items: ["A", "B", "C"] },
|
||||
{ type: "lower-alpha", title: "Lower alpha", items: ["a", "b", "c"] },
|
||||
{
|
||||
type: "upper-roman",
|
||||
title: "Upper Roman",
|
||||
items: ["I", "II", "III"],
|
||||
},
|
||||
{
|
||||
type: "lower-roman",
|
||||
title: "Lower Roman",
|
||||
items: ["i", "ii", "iii"],
|
||||
},
|
||||
{ type: "lower-greek", title: "Lower Greek", items: ["α", "β", "γ"] },
|
||||
],
|
||||
};
|
||||
return _super.call(this, "numberedList", "Numbered list", options) || this;
|
||||
}
|
||||
return NumberedList;
|
||||
}(ListTool));
|
||||
export { NumberedList };
|
||||
var BulletList = /** @class */ (function (_super) {
|
||||
__extends(BulletList, _super);
|
||||
function BulletList() {
|
||||
var options = {
|
||||
type: "bulletList",
|
||||
icon: "bulletList",
|
||||
onClick: function (editor) { return editor.chain().focus().toggleOrderedList().run(); },
|
||||
subTypes: [
|
||||
{ type: "disc", title: "Decimal", items: ["1", "2", "3"] },
|
||||
{ type: "circle", title: "Upper alpha", items: ["A", "B", "C"] },
|
||||
{ type: "square", title: "Lower alpha", items: ["a", "b", "c"] },
|
||||
],
|
||||
};
|
||||
return _super.call(this, "bulletList", "Bullet list", options) || this;
|
||||
}
|
||||
return BulletList;
|
||||
}(ListTool));
|
||||
export { BulletList };
|
||||
function ListThumbnail(props) {
|
||||
var listStyleType = props.listStyleType;
|
||||
return (_jsx(Flex, __assign({ as: "ul", sx: {
|
||||
flexDirection: "column",
|
||||
flex: 1,
|
||||
p: 0,
|
||||
listStyleType: listStyleType,
|
||||
} }, { children: [0, 0, 0].map(function () { return (_jsx(Box, __assign({ as: "li", sx: {
|
||||
display: "list-item",
|
||||
color: "text",
|
||||
fontSize: 8,
|
||||
mb: "1px",
|
||||
} }, { children: _jsx(Flex, __assign({ sx: {
|
||||
alignItems: "center",
|
||||
} }, { children: _jsx(Box, { sx: {
|
||||
width: "100%",
|
||||
flexShrink: 0,
|
||||
height: 4,
|
||||
bg: "#cbcbcb",
|
||||
borderRadius: "2px",
|
||||
} }) })) }))); }) })));
|
||||
}
|
||||
19
packages/editor/dist/toolbar/tools/textdirection.d.ts
vendored
Normal file
19
packages/editor/dist/toolbar/tools/textdirection.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/// <reference types="react" />
|
||||
import { ITool, ToolProps } from "../types";
|
||||
import { ToolId } from ".";
|
||||
import { IconNames } from "../icons";
|
||||
declare class TextDirectionTool<TId extends ToolId, TTitle extends string> implements ITool {
|
||||
readonly id: TId;
|
||||
readonly title: TTitle;
|
||||
private readonly icon;
|
||||
private readonly direction;
|
||||
constructor(id: TId, title: TTitle, icon: IconNames, direction: "ltr" | "rtl");
|
||||
render: (props: ToolProps) => JSX.Element;
|
||||
}
|
||||
export declare class LeftToRight extends TextDirectionTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export declare class RightToLeft extends TextDirectionTool<ToolId, string> {
|
||||
constructor();
|
||||
}
|
||||
export {};
|
||||
49
packages/editor/dist/toolbar/tools/textdirection.js
vendored
Normal file
49
packages/editor/dist/toolbar/tools/textdirection.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
import { ToolButton } from "../components/tool-button";
|
||||
var TextDirectionTool = /** @class */ (function () {
|
||||
function TextDirectionTool(id, title, icon, direction) {
|
||||
var _this = this;
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.direction = direction;
|
||||
this.render = function (props) {
|
||||
var editor = props.editor;
|
||||
return (_jsx(ToolButton, { title: _this.title, id: _this.id, icon: _this.icon, onClick: function () {
|
||||
return editor.chain().focus().setTextDirection(_this.direction).run();
|
||||
}, toggled: editor.isActive({ textDirection: _this.direction }) }));
|
||||
};
|
||||
}
|
||||
return TextDirectionTool;
|
||||
}());
|
||||
var LeftToRight = /** @class */ (function (_super) {
|
||||
__extends(LeftToRight, _super);
|
||||
function LeftToRight() {
|
||||
return _super.call(this, "ltr", "Left-to-right", "ltr", "ltr") || this;
|
||||
}
|
||||
return LeftToRight;
|
||||
}(TextDirectionTool));
|
||||
export { LeftToRight };
|
||||
var RightToLeft = /** @class */ (function (_super) {
|
||||
__extends(RightToLeft, _super);
|
||||
function RightToLeft() {
|
||||
return _super.call(this, "rtl", "Right-to-left", "rtl", "rtl") || this;
|
||||
}
|
||||
return RightToLeft;
|
||||
}(TextDirectionTool));
|
||||
export { RightToLeft };
|
||||
12
packages/editor/dist/toolbar/types.d.ts
vendored
Normal file
12
packages/editor/dist/toolbar/types.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/// <reference types="react" />
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { ToolId } from "./tools";
|
||||
export declare type ToolProps = {
|
||||
editor: Editor;
|
||||
};
|
||||
export interface ITool {
|
||||
id: ToolId;
|
||||
title: string;
|
||||
description?: string;
|
||||
render(props: ToolProps): JSX.Element;
|
||||
}
|
||||
4
packages/editor/dist/toolbar/types.js
vendored
Normal file
4
packages/editor/dist/toolbar/types.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export {};
|
||||
// export interface ToolConstructor {
|
||||
// new (editor: Editor): ITool;
|
||||
// }
|
||||
@@ -1,28 +0,0 @@
|
||||
import CharacterCount from "@tiptap/extension-character-count";
|
||||
import Placeholder from "@tiptap/extension-placeholder";
|
||||
import { EditorOptions, useEditor } from "@tiptap/react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export const useTiptap = (options: Partial<EditorOptions> = {}, deps?: any) => {
|
||||
const defaultOptions = useMemo<Partial<EditorOptions>>(
|
||||
() => ({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
CharacterCount,
|
||||
Placeholder.configure({
|
||||
placeholder: "Start writing your note...",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const editor = useEditor({ ...defaultOptions, ...options }, deps);
|
||||
|
||||
/**
|
||||
* Add editor to global for use in React Native.
|
||||
*/
|
||||
global.editor = editor;
|
||||
return editor;
|
||||
};
|
||||
2951
packages/editor/package-lock.json
generated
2951
packages/editor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,25 +2,61 @@
|
||||
"name": "notesnook-editor",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "./",
|
||||
"main": "./dist/index.js",
|
||||
"dependencies": {
|
||||
"@tiptap/extension-history": "^2.0.0-beta.21",
|
||||
"@mdi/js": "^6.6.96",
|
||||
"@mdi/react": "^1.5.0",
|
||||
"@notesnook/theme": "file:../themeprovider",
|
||||
"@rebass/forms": "^4.0.6",
|
||||
"@tiptap/extension-character-count": "^2.0.0-beta.24",
|
||||
"@tiptap/extension-color": "^2.0.0-beta.9",
|
||||
"@tiptap/extension-font-family": "^2.0.0-beta.21",
|
||||
"@tiptap/extension-highlight": "^2.0.0-beta.33",
|
||||
"@tiptap/extension-history": "^2.0.0-beta.21",
|
||||
"@tiptap/extension-horizontal-rule": "^2.0.0-beta.31",
|
||||
"@tiptap/extension-link": "^2.0.0-beta.36",
|
||||
"@tiptap/extension-placeholder": "^2.0.0-beta.45",
|
||||
"@tiptap/extension-subscript": "^2.0.0-beta.10",
|
||||
"@tiptap/extension-superscript": "^2.0.0-beta.10",
|
||||
"@tiptap/extension-table": "^2.0.0-beta.48",
|
||||
"@tiptap/extension-table-cell": "^2.0.0-beta.20",
|
||||
"@tiptap/extension-table-header": "^2.0.0-beta.22",
|
||||
"@tiptap/extension-table-row": "^2.0.0-beta.19",
|
||||
"@tiptap/extension-text-align": "^2.0.0-beta.29",
|
||||
"@tiptap/extension-text-style": "^2.0.0-beta.23",
|
||||
"@tiptap/extension-underline": "^2.0.0-beta.23",
|
||||
"@tiptap/react": "^2.0.0-beta.98",
|
||||
"@tiptap/starter-kit": "^2.0.0-beta.150"
|
||||
"@tiptap/starter-kit": "^2.0.0-beta.150",
|
||||
"@types/rebass": "^4.0.10",
|
||||
"@types/rebass__forms": "^4.0.6",
|
||||
"emotion-theming": "^10.0.19",
|
||||
"prosemirror-tables": "^1.1.1",
|
||||
"re-resizable": "^6.9.5",
|
||||
"react-color": "^2.19.3",
|
||||
"react-modal": "^3.14.4",
|
||||
"react-toggle": "^4.1.2",
|
||||
"reactjs-popup": "^2.0.5",
|
||||
"rebass": "^4.0.7",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"tippy.js": "^6.3.7",
|
||||
"zustand": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.11",
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-color": "^3.0.6",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"@types/react-modal": "^3.13.1",
|
||||
"@types/react-toggle": "^4.0.3",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "4.0.3",
|
||||
"typescript": "^4.5.2",
|
||||
"typescript-plugin-css-modules": "^3.4.0",
|
||||
"web-vitals": "^1.1.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "react-scripts build"
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
||||
|
||||
1
packages/editor/src/components/menu/index.ts
Normal file
1
packages/editor/src/components/menu/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { MenuPresenter } from "./menu";
|
||||
377
packages/editor/src/components/menu/menu.tsx
Normal file
377
packages/editor/src/components/menu/menu.tsx
Normal file
@@ -0,0 +1,377 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useRef,
|
||||
useEffect,
|
||||
useState,
|
||||
PropsWithChildren,
|
||||
} from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Box, Flex, FlexProps, Text } from "rebass";
|
||||
import { getPosition, MenuOptions } from "./useMenu";
|
||||
// import { FlexScrollContainer } from "../scrollcontainer";
|
||||
import MenuItem from "./menuitem";
|
||||
import { MenuItem as MenuItemType /*ResolvedMenuItem*/ } from "./types";
|
||||
// import { useMenuTrigger, useMenu, getPosition } from "../../hooks/useMenu";
|
||||
import Modal from "react-modal";
|
||||
import { ThemeProvider } from "emotion-theming";
|
||||
// import { store as selectionStore } from "../../stores/selectionstore";
|
||||
|
||||
function useMenuFocus(
|
||||
items: MenuItemType[],
|
||||
onAction: (event: KeyboardEvent) => void,
|
||||
onClose: (event: KeyboardEvent) => void
|
||||
) {
|
||||
const [focusIndex, setFocusIndex] = useState(-1);
|
||||
const [isSubmenuOpen, setIsSubmenuOpen] = useState(false);
|
||||
|
||||
const moveItemIntoView = useCallback(
|
||||
(index) => {
|
||||
const item = items[index];
|
||||
if (!item) return;
|
||||
const element = document.getElementById(item.key);
|
||||
if (!element) return;
|
||||
element.scrollIntoView({
|
||||
behavior: "auto",
|
||||
});
|
||||
},
|
||||
[items]
|
||||
);
|
||||
|
||||
const onKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
const isSeperator = (i: number) =>
|
||||
items && (items[i]?.type === "seperator" || items[i]?.isDisabled);
|
||||
const moveDown = (i: number) => (i < items.length - 1 ? ++i : 0);
|
||||
const moveUp = (i: number) => (i > 0 ? --i : items.length - 1);
|
||||
const hasSubmenu = (i: number) => items && items[i]?.hasSubmenu;
|
||||
const openSubmenu = (index: number) => {
|
||||
if (!hasSubmenu(index)) return;
|
||||
setIsSubmenuOpen(true);
|
||||
};
|
||||
|
||||
const closeSubmenu = (index: number) => {
|
||||
if (!hasSubmenu(index)) return;
|
||||
setIsSubmenuOpen(false);
|
||||
};
|
||||
|
||||
setFocusIndex((i) => {
|
||||
let nextIndex = i;
|
||||
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
if (isSubmenuOpen) break;
|
||||
nextIndex = moveUp(i);
|
||||
while (isSeperator(nextIndex)) {
|
||||
nextIndex = moveUp(nextIndex);
|
||||
}
|
||||
break;
|
||||
case "ArrowDown":
|
||||
if (isSubmenuOpen) break;
|
||||
nextIndex = moveDown(i);
|
||||
while (isSeperator(nextIndex)) {
|
||||
nextIndex = moveDown(nextIndex);
|
||||
}
|
||||
break;
|
||||
case "ArrowRight":
|
||||
openSubmenu(i);
|
||||
break;
|
||||
case "ArrowLeft":
|
||||
closeSubmenu(i);
|
||||
break;
|
||||
case "Enter":
|
||||
onAction && onAction(e);
|
||||
break;
|
||||
case "Escape":
|
||||
onClose && onClose(e);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (nextIndex !== i) moveItemIntoView(nextIndex);
|
||||
|
||||
return nextIndex;
|
||||
});
|
||||
},
|
||||
[items, isSubmenuOpen, moveItemIntoView, onAction]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
}, [onKeyDown]);
|
||||
|
||||
return { focusIndex, setFocusIndex, isSubmenuOpen, setIsSubmenuOpen };
|
||||
}
|
||||
|
||||
type MenuProps = MenuContainerProps & {
|
||||
items: MenuItemType[];
|
||||
closeMenu: () => void;
|
||||
};
|
||||
|
||||
export function Menu(props: MenuProps) {
|
||||
const { items, title, closeMenu, ...containerProps } = props;
|
||||
const hoverTimeout = useRef<NodeJS.Timeout>();
|
||||
const onAction = useCallback(
|
||||
(e, item) => {
|
||||
e.stopPropagation();
|
||||
if (closeMenu) closeMenu();
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
}
|
||||
},
|
||||
[closeMenu]
|
||||
);
|
||||
|
||||
const { focusIndex, setFocusIndex, isSubmenuOpen, setIsSubmenuOpen } =
|
||||
useMenuFocus(
|
||||
items,
|
||||
(e) => {
|
||||
const item = items[focusIndex];
|
||||
if (item) onAction(e, item);
|
||||
},
|
||||
() => closeMenu()
|
||||
);
|
||||
|
||||
const subMenuRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
const item = items[focusIndex];
|
||||
if (!item || !subMenuRef.current) return;
|
||||
|
||||
const menuItemElement = document.getElementById(item.key);
|
||||
if (!menuItemElement) return;
|
||||
|
||||
if (!isSubmenuOpen) {
|
||||
subMenuRef.current.style.visibility = "hidden";
|
||||
return;
|
||||
}
|
||||
|
||||
const { top, left } = getPosition(subMenuRef.current, {
|
||||
yOffset: menuItemElement.offsetHeight,
|
||||
target: menuItemElement,
|
||||
location: "right",
|
||||
});
|
||||
|
||||
subMenuRef.current.style.visibility = "visible";
|
||||
subMenuRef.current.style.top = `${top}px`;
|
||||
subMenuRef.current.style.left = `${left}px`;
|
||||
}, [isSubmenuOpen, focusIndex, items]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuContainer {...containerProps}>
|
||||
{items.map((item, index) => (
|
||||
<MenuItem
|
||||
key={item.key}
|
||||
item={item}
|
||||
onClick={(e) => {
|
||||
if (item.items?.length) {
|
||||
setFocusIndex(index);
|
||||
setIsSubmenuOpen(true);
|
||||
} else onAction(e, item);
|
||||
}}
|
||||
isFocused={focusIndex === index}
|
||||
onMouseEnter={() => {
|
||||
if (item.isDisabled) {
|
||||
setFocusIndex(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hoverTimeout.current) clearTimeout(hoverTimeout.current);
|
||||
setFocusIndex(index);
|
||||
setIsSubmenuOpen(false);
|
||||
if (item.items?.length) {
|
||||
hoverTimeout.current = setTimeout(() => {
|
||||
setIsSubmenuOpen(true);
|
||||
}, 500);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (hoverTimeout.current) clearTimeout(hoverTimeout.current);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</MenuContainer>
|
||||
{isSubmenuOpen && (
|
||||
<Flex
|
||||
ref={subMenuRef}
|
||||
style={{ visibility: "hidden" }}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
}}
|
||||
>
|
||||
<Menu items={items[focusIndex]?.items || []} closeMenu={closeMenu} />
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
type MenuContainerProps = FlexProps & {
|
||||
title?: string;
|
||||
};
|
||||
function MenuContainer(props: PropsWithChildren<MenuContainerProps>) {
|
||||
const { children, title, sx, ...flexProps } = props;
|
||||
|
||||
return (
|
||||
<Box
|
||||
className="menuContainer"
|
||||
as="ul"
|
||||
tabIndex={-1}
|
||||
sx={{
|
||||
bg: "background",
|
||||
py: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
listStyle: "none",
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
borderRadius: "default",
|
||||
boxShadow: "menu",
|
||||
border: "1px solid var(--border)",
|
||||
width: 220,
|
||||
...sx,
|
||||
}}
|
||||
{...flexProps}
|
||||
>
|
||||
{title && (
|
||||
<Text
|
||||
sx={{
|
||||
fontFamily: "body",
|
||||
fontSize: "subtitle",
|
||||
color: "primary",
|
||||
py: "8px",
|
||||
px: 3,
|
||||
borderBottom: "1px solid",
|
||||
borderBottomColor: "border",
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
{children}
|
||||
{/* <FlexScrollContainer>{children}</FlexScrollContainer> */}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
type MenuPresenterProps = MenuContainerProps & {
|
||||
items: MenuItemType[];
|
||||
options: MenuOptions;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
className?: string;
|
||||
};
|
||||
export function MenuPresenter(props: PropsWithChildren<MenuPresenterProps>) {
|
||||
const {
|
||||
className,
|
||||
options,
|
||||
items,
|
||||
isOpen,
|
||||
onClose,
|
||||
children,
|
||||
...containerProps
|
||||
} = props;
|
||||
// const { isOpen, closeMenu } = useMenuTrigger();
|
||||
// const { items, } = useMenu();
|
||||
const { position, type } = options;
|
||||
const isAutocomplete = type === "autocomplete";
|
||||
const contentRef = useRef<HTMLDivElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!contentRef.current || !position) return;
|
||||
const menu = contentRef.current;
|
||||
const menuPosition = getPosition(menu, position);
|
||||
menu.style.top = menuPosition.top + "px";
|
||||
menu.style.left = menuPosition.left + "px";
|
||||
}, [position]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
contentRef={(ref) => (contentRef.current = ref)}
|
||||
className={className || "menuContainer"}
|
||||
role="menu"
|
||||
isOpen={isOpen}
|
||||
appElement={document.body}
|
||||
shouldCloseOnEsc
|
||||
shouldReturnFocusAfterClose
|
||||
shouldCloseOnOverlayClick
|
||||
shouldFocusAfterRender={!isAutocomplete}
|
||||
ariaHideApp={!isAutocomplete}
|
||||
preventScroll={!isAutocomplete}
|
||||
onRequestClose={onClose}
|
||||
portalClassName={className || "menuPresenter"}
|
||||
onAfterOpen={(obj) => {
|
||||
if (!obj || !position) return;
|
||||
const { contentEl: menu } = obj;
|
||||
const menuPosition = getPosition(menu, position);
|
||||
menu.style.top = menuPosition.top + "px";
|
||||
menu.style.left = menuPosition.left + "px";
|
||||
}}
|
||||
overlayElement={(props, contentEl) => {
|
||||
return (
|
||||
<Box
|
||||
{...props}
|
||||
style={{
|
||||
...props.style,
|
||||
position: isAutocomplete ? "initial" : "fixed",
|
||||
zIndex: 1000,
|
||||
backgroundColor: isAutocomplete ? "transparent" : "unset",
|
||||
}}
|
||||
// onClick={(e) => {
|
||||
// if (!(e.target instanceof HTMLElement)) return;
|
||||
// console.log(e.target.closest(".ReactModal__Content"));
|
||||
// if (e.target.closest(".ReactModal__Content")) return;
|
||||
// onClose();
|
||||
// }}
|
||||
// onContextMenu={(e) => {
|
||||
// e.preventDefault();
|
||||
// onClose();
|
||||
// }}
|
||||
>
|
||||
{contentEl}
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
contentElement={(props, children) => (
|
||||
<Box
|
||||
{...props}
|
||||
style={{}}
|
||||
sx={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
width: "fit-content",
|
||||
height: "fit-content",
|
||||
position: "absolute",
|
||||
backgroundColor: undefined,
|
||||
padding: 0,
|
||||
zIndex: 0,
|
||||
outline: 0,
|
||||
isolation: "isolate",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
)}
|
||||
style={{
|
||||
content: {},
|
||||
overlay: {
|
||||
zIndex: 999,
|
||||
background: "transparent",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.children ? (
|
||||
props.children
|
||||
) : (
|
||||
<Menu items={items} closeMenu={onClose} {...containerProps} />
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
121
packages/editor/src/components/menu/menuitem.tsx
Normal file
121
packages/editor/src/components/menu/menuitem.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
// import { Check, ChevronRight, Pro } from "../icons";
|
||||
import { useRef } from "react";
|
||||
import { Flex, Box, Text, Button } from "rebass";
|
||||
import { Icon } from "../../toolbar/components/icon";
|
||||
import { Icons } from "../../toolbar/icons";
|
||||
import { MenuItem /*ResolvedMenuItem*/ } from "./types";
|
||||
|
||||
type MenuItemProps = {
|
||||
// item: ResolvedMenuItem<any>;
|
||||
item: MenuItem;
|
||||
isFocused: boolean;
|
||||
onMouseEnter: () => void;
|
||||
onMouseLeave: () => void;
|
||||
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
|
||||
function MenuItem(props: MenuItemProps) {
|
||||
const { item, isFocused, onMouseEnter, onMouseLeave, onClick } = props;
|
||||
const {
|
||||
title,
|
||||
key,
|
||||
// color,
|
||||
icon,
|
||||
// iconColor,
|
||||
type,
|
||||
tooltip,
|
||||
isDisabled,
|
||||
isChecked,
|
||||
hasSubmenu,
|
||||
component: Component,
|
||||
modifier,
|
||||
} = item;
|
||||
const itemRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
if (type === "seperator")
|
||||
return (
|
||||
<Box
|
||||
as="li"
|
||||
key={key}
|
||||
sx={{
|
||||
width: "95%",
|
||||
height: "0.5px",
|
||||
bg: "border",
|
||||
my: 2,
|
||||
alignSelf: "center",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
as="li"
|
||||
sx={{ flex: 1, flexDirection: "column" }}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<Button
|
||||
id={key}
|
||||
data-test-id={`menuitem-${key}`}
|
||||
key={key}
|
||||
ref={itemRef}
|
||||
tabIndex={-1}
|
||||
variant="menuitem"
|
||||
title={tooltip}
|
||||
disabled={isDisabled}
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
bg: isFocused ? "hover" : "transparent",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
{Component ? (
|
||||
<Component />
|
||||
) : (
|
||||
<>
|
||||
<Flex>
|
||||
{icon && (
|
||||
<Icon
|
||||
path={Icons[icon]}
|
||||
color={"text"}
|
||||
size={15}
|
||||
sx={{ mr: 2 }}
|
||||
/>
|
||||
)}
|
||||
<Text
|
||||
as="span"
|
||||
sx={{
|
||||
fontFamily: "body",
|
||||
fontSize: "menu",
|
||||
color: "text",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex>
|
||||
{isChecked && <Icon path={Icons.check} size={14} />}
|
||||
{/*
|
||||
{hasSubmenu && <ChevronRight size={14} />} */}
|
||||
{modifier && (
|
||||
<Text
|
||||
as="span"
|
||||
sx={{
|
||||
fontFamily: "body",
|
||||
fontSize: "menu",
|
||||
color: "fontTertiary",
|
||||
}}
|
||||
>
|
||||
{modifier}
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
export default MenuItem;
|
||||
37
packages/editor/src/components/menu/types.ts
Normal file
37
packages/editor/src/components/menu/types.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// export type ResolverFunction<T, TData> = (
|
||||
// data: any,
|
||||
// item: MenuItem<TData>
|
||||
// ) => T;
|
||||
// export type Resolvable<T, TData> = T | ResolverFunction<T, TData>;
|
||||
// export type MenuItem<TData> = {
|
||||
// type: "menuitem" | "seperator";
|
||||
// key: string;
|
||||
// component?: Resolvable<(props: any) => JSX.Element, TData>;
|
||||
// onClick?: (data: TData, item: MenuItem<TData>) => void;
|
||||
// title?: Resolvable<string, TData>;
|
||||
// icon?: Resolvable<string, TData>;
|
||||
// tooltip?: Resolvable<string, TData>;
|
||||
// disabled?: Resolvable<string, TData>;
|
||||
// hidden?: Resolvable<boolean, TData>;
|
||||
// checked?: Resolvable<boolean, TData>;
|
||||
// modifier?: Resolvable<string[], TData>;
|
||||
// items?: Resolvable<MenuItem<TData>[], TData>;
|
||||
// };
|
||||
|
||||
import { IconNames } from "../../toolbar/icons";
|
||||
|
||||
export type MenuItem = {
|
||||
type: "menuitem" | "seperator";
|
||||
key: string;
|
||||
component?: (props: any) => JSX.Element;
|
||||
onClick?: () => void;
|
||||
title?: string;
|
||||
icon?: IconNames;
|
||||
tooltip?: string;
|
||||
isDisabled?: boolean;
|
||||
isHidden?: boolean;
|
||||
isChecked?: boolean;
|
||||
hasSubmenu?: boolean;
|
||||
modifier?: string;
|
||||
items?: MenuItem[];
|
||||
};
|
||||
296
packages/editor/src/components/menu/useMenu.ts
Normal file
296
packages/editor/src/components/menu/useMenu.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
import create from "zustand";
|
||||
import shallow from "zustand/shallow";
|
||||
import {
|
||||
MenuItem,
|
||||
// Resolvable,
|
||||
// ResolvedMenuItem,
|
||||
// ResolverFunction,
|
||||
} from "./types";
|
||||
|
||||
type PositionData = {
|
||||
x: number;
|
||||
y: number;
|
||||
actualX: number;
|
||||
actualY: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
};
|
||||
|
||||
const mousePosition: PositionData = { x: 0, y: 0, actualX: 0, actualY: 0 };
|
||||
window.addEventListener("mousemove", (e) => {
|
||||
const { x, y, actualX, actualY } = getMousePosition(e);
|
||||
mousePosition.x = x;
|
||||
mousePosition.y = y;
|
||||
mousePosition.actualX = actualX;
|
||||
mousePosition.actualY = actualY;
|
||||
});
|
||||
|
||||
export type MenuOptions = {
|
||||
type: "autocomplete" | "menu";
|
||||
position?: PositionOptions;
|
||||
};
|
||||
// interface IMenuStore {
|
||||
// isOpen?: boolean;
|
||||
// // items?: ResolvedMenuItem<any>[];
|
||||
// items?: MenuItem[];
|
||||
// title?: string;
|
||||
// options?: MenuOptions;
|
||||
// //data?: any;
|
||||
|
||||
// // open: <TData>(items: MenuItem<TData>[], data: TData) => void;
|
||||
// open: (items: MenuItem[]) => void;
|
||||
// close: () => void;
|
||||
// }
|
||||
|
||||
// const useMenuStore = create<IMenuStore>((set) => ({
|
||||
// isOpen: false,
|
||||
// items: [],
|
||||
// title: undefined,
|
||||
// options: undefined,
|
||||
// // data: undefined,
|
||||
// // open: <TData>(items: MenuItem<TData>[], data: TData) =>
|
||||
// // set((state) => {
|
||||
// // state.isOpen = true;
|
||||
// // state.items = mapMenuItems(items, data);
|
||||
// // // state.data = data;
|
||||
// // }),
|
||||
// open: (items: MenuItem[], options?: MenuOptions) =>
|
||||
// set((state) => {
|
||||
// state.isOpen = true;
|
||||
// state.items = items.filter((item) => !item.isHidden);
|
||||
// state.options = options;
|
||||
// // state.data = data;
|
||||
// }),
|
||||
// close: () =>
|
||||
// set((state) => {
|
||||
// state.isOpen = false;
|
||||
// state.items = [];
|
||||
// state.options = undefined;
|
||||
// // state.data = undefined;
|
||||
// state.title = undefined;
|
||||
// }),
|
||||
// }));
|
||||
|
||||
// export function useMenuTrigger() {
|
||||
// const isOpen = useMenuStore((store) => store.isOpen);
|
||||
// const [open, close] = useMenuStore(
|
||||
// (store) => [store.open, store.close],
|
||||
// shallow
|
||||
// );
|
||||
|
||||
// return {
|
||||
// openMenu: open,
|
||||
// closeMenu: close,
|
||||
// isOpen,
|
||||
// };
|
||||
// }
|
||||
|
||||
// export function useMenu() {
|
||||
// const [items, options] = useMenuStore((store) => [
|
||||
// store.items,
|
||||
// store.options,
|
||||
// ]);
|
||||
// return { items, options };
|
||||
// }
|
||||
|
||||
type PositionOptions = {
|
||||
target?: HTMLElement | "mouse";
|
||||
isTargetAbsolute?: boolean;
|
||||
location?: "right" | "left" | "below" | "top";
|
||||
align?: "center" | "start" | "end";
|
||||
yOffset?: number;
|
||||
xOffset?: number;
|
||||
yAnchor?: HTMLElement;
|
||||
parent?: HTMLElement | Element;
|
||||
};
|
||||
export function getPosition(
|
||||
element: HTMLElement,
|
||||
options: PositionOptions
|
||||
): { top: number; left: number } {
|
||||
const {
|
||||
target = "mouse",
|
||||
isTargetAbsolute = false,
|
||||
location = undefined,
|
||||
yOffset = 0,
|
||||
xOffset = 0,
|
||||
align = "start",
|
||||
parent = document.body,
|
||||
yAnchor,
|
||||
} = options || {};
|
||||
|
||||
const { x, y, width, height, actualX, actualY } =
|
||||
target === "mouse"
|
||||
? mousePosition
|
||||
: getElementPosition(target, isTargetAbsolute);
|
||||
|
||||
const elementWidth = element.offsetWidth;
|
||||
const elementHeight = element.offsetHeight;
|
||||
|
||||
const windowWidth = parent.clientWidth;
|
||||
const windowHeight = parent.clientHeight - 20;
|
||||
|
||||
let position = { top: 0, left: 0 };
|
||||
|
||||
if (windowWidth - actualX < elementWidth) {
|
||||
const xDiff = actualX - x;
|
||||
position.left = windowWidth - elementWidth;
|
||||
position.left -= xDiff;
|
||||
} else {
|
||||
position.left = x;
|
||||
}
|
||||
|
||||
if (width) {
|
||||
if (location === "right") position.left += width;
|
||||
else if (location === "left") position.left -= elementWidth;
|
||||
}
|
||||
|
||||
if (windowHeight - actualY < elementHeight) {
|
||||
const yDiff = actualY - y;
|
||||
position.top = windowHeight - elementHeight;
|
||||
position.top -= yDiff;
|
||||
} else {
|
||||
position.top = y;
|
||||
}
|
||||
|
||||
if (height) {
|
||||
if (location === "below") position.top += height;
|
||||
else if (location === "top") position.top -= height;
|
||||
}
|
||||
|
||||
if (target !== "mouse" && align === "center" && elementWidth > 0) {
|
||||
position.left -= elementWidth / 2 - target.clientWidth / 2;
|
||||
}
|
||||
|
||||
// Adjust menu height
|
||||
if (elementHeight > windowHeight - position.top) {
|
||||
element.style.maxHeight = `${windowHeight - 20}px`;
|
||||
}
|
||||
|
||||
if (yAnchor) {
|
||||
const anchorY = getElementPosition(yAnchor, isTargetAbsolute);
|
||||
position.top = anchorY.actualY - elementHeight;
|
||||
}
|
||||
|
||||
position.top = position.top < 0 ? 0 : position.top;
|
||||
position.left = position.left < 0 ? 0 : position.left;
|
||||
position.top += yOffset;
|
||||
position.left += xOffset;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
function getMousePosition(e: MouseEvent) {
|
||||
var posx = 0;
|
||||
var posy = 0;
|
||||
|
||||
if (!e && window.event) e = window.event as MouseEvent;
|
||||
|
||||
if (e.pageX || e.pageY) {
|
||||
posx = e.pageX;
|
||||
posy = e.pageY;
|
||||
} else if (e.clientX || e.clientY) {
|
||||
posx =
|
||||
e.clientX +
|
||||
document.body.scrollLeft +
|
||||
document.documentElement.scrollLeft;
|
||||
posy =
|
||||
e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
||||
}
|
||||
|
||||
return {
|
||||
x: posx,
|
||||
y: posy,
|
||||
actualY: posy,
|
||||
actualX: posx,
|
||||
};
|
||||
}
|
||||
|
||||
export function getElementPosition(
|
||||
element: HTMLElement,
|
||||
absolute: boolean
|
||||
): PositionData {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const position: PositionData = {
|
||||
x: element.offsetLeft,
|
||||
y: element.offsetTop,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
actualY: rect.y,
|
||||
actualX: rect.x,
|
||||
};
|
||||
if (absolute) {
|
||||
position.x = position.actualX;
|
||||
position.y = position.actualY;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
// function mapMenuItems<TData>(
|
||||
// items: MenuItem<TData>[],
|
||||
// data: TData
|
||||
// ): ResolvedMenuItem<TData>[] {
|
||||
// return items.reduce((prev, item) => {
|
||||
// const { key, onClick: _onClick, disabled, hidden, checked, type } = item;
|
||||
|
||||
// const isHidden = resolveProp(hidden, data, item);
|
||||
// if (isHidden) return prev;
|
||||
|
||||
// const isSeperator = type === "seperator";
|
||||
// if (isSeperator) {
|
||||
// prev.push({ isSeperator: true });
|
||||
// return prev;
|
||||
// }
|
||||
|
||||
// const title = resolveProp(item.title, data, item);
|
||||
// const icon = resolveProp(item.icon, data, item);
|
||||
// const isChecked = resolveProp(checked, data, item);
|
||||
// const isDisabled = resolveProp(disabled, data, item);
|
||||
// const items = resolveProp(item.items, data, item);
|
||||
// const modifier = resolveProp(item.modifier, data, item);
|
||||
// const onClick =
|
||||
// typeof _onClick === "function" && _onClick.bind(this, data, item);
|
||||
|
||||
// const tooltip =
|
||||
// isDisabled || resolveProp(item.tooltip, data, item) || title;
|
||||
// const hasSubmenu = items?.length > 0;
|
||||
|
||||
// const menuItem: ResolvedMenuItem<TData> = {
|
||||
// type,
|
||||
// title,
|
||||
// key,
|
||||
// onClick,
|
||||
// tooltip,
|
||||
|
||||
// isChecked,
|
||||
// isDisabled: !!isDisabled,
|
||||
// isHidden,
|
||||
// hasSubmenu,
|
||||
// icon,
|
||||
// modifier: modifier?.join("+"),
|
||||
// };
|
||||
|
||||
// if (hasSubmenu)
|
||||
// menuItem.items = mapMenuItems(items, { ...data, parent: menuItem });
|
||||
|
||||
// prev.push(menuItem);
|
||||
|
||||
// return prev;
|
||||
// }, []);
|
||||
// }
|
||||
|
||||
// function resolveProp<T, TData>(
|
||||
// prop: Resolvable<T, TData>,
|
||||
// data: any,
|
||||
// item: MenuItem<TData>
|
||||
// ): T {
|
||||
// if (typeof prop === "function" && (prop as any).isReactComponent) {
|
||||
// return prop as T;
|
||||
// }
|
||||
// return isResolverFunction<T, TData>(prop) ? prop(data, item) : prop;
|
||||
// }
|
||||
|
||||
// function isResolverFunction<T, TData>(
|
||||
// prop: any
|
||||
// ): prop is ResolverFunction<T, TData> {
|
||||
// return typeof prop === "function";
|
||||
// }
|
||||
46
packages/editor/src/components/toggle/index.tsx
Normal file
46
packages/editor/src/components/toggle/index.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import ReactToggle, { ToggleProps } from "react-toggle";
|
||||
import "react-toggle/style.css";
|
||||
|
||||
const css = `.react-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.react-toggle-thumb {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.react-toggle-track {
|
||||
width: 30px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.react-toggle-thumb {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
top: 0px;
|
||||
left: 1px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-thumb {
|
||||
left: 13px;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.react-toggle--focus .react-toggle-thumb {
|
||||
box-shadow: none;
|
||||
}
|
||||
`;
|
||||
export function Toggle(props: ToggleProps) {
|
||||
return (
|
||||
<>
|
||||
<style>{css}</style>
|
||||
<ReactToggle size={20} onChange={() => {}} icons={false} {...props} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
21
packages/editor/src/extensions/bullet-list/bullet-list.ts
Normal file
21
packages/editor/src/extensions/bullet-list/bullet-list.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import TiptapBulletList from "@tiptap/extension-bullet-list";
|
||||
|
||||
export const BulletList = TiptapBulletList.extend({
|
||||
addAttributes() {
|
||||
return {
|
||||
listType: {
|
||||
default: null,
|
||||
parseHTML: (element) => element.style.listStyleType,
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.listType) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
style: `list-style-type: ${attributes.listType}`,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
5
packages/editor/src/extensions/bullet-list/index.ts
Normal file
5
packages/editor/src/extensions/bullet-list/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { BulletList } from "./bullet-list";
|
||||
|
||||
export * from "./bullet-list";
|
||||
|
||||
export default BulletList;
|
||||
72
packages/editor/src/extensions/font-size/font-size.ts
Normal file
72
packages/editor/src/extensions/font-size/font-size.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import "@tiptap/extension-text-style";
|
||||
|
||||
type FontSizeOptions = {
|
||||
types: string[];
|
||||
defaultFontSize: number;
|
||||
};
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
fontSize: {
|
||||
/**
|
||||
* Set the font family
|
||||
*/
|
||||
setFontSize: (fontSize: string) => ReturnType;
|
||||
/**
|
||||
* Unset the font family
|
||||
*/
|
||||
unsetFontSize: () => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const FontSize = Extension.create<FontSizeOptions>({
|
||||
name: "fontSize",
|
||||
|
||||
defaultOptions: {
|
||||
types: ["textStyle"],
|
||||
defaultFontSize: 16,
|
||||
},
|
||||
|
||||
addGlobalAttributes() {
|
||||
return [
|
||||
{
|
||||
types: this.options.types,
|
||||
attributes: {
|
||||
fontSize: {
|
||||
default: `${this.options.defaultFontSize}px`,
|
||||
parseHTML: (element) => element.style.fontSize,
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.fontSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
style: `font-size: ${attributes.fontSize}`,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setFontSize:
|
||||
(fontSize) =>
|
||||
({ chain }) => {
|
||||
return chain().setMark("textStyle", { fontSize }).run();
|
||||
},
|
||||
unsetFontSize:
|
||||
() =>
|
||||
({ chain }) => {
|
||||
return chain()
|
||||
.setMark("textStyle", { fontSize: null })
|
||||
.removeEmptyTextStyle()
|
||||
.run();
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
5
packages/editor/src/extensions/font-size/index.ts
Normal file
5
packages/editor/src/extensions/font-size/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { FontSize } from "./font-size";
|
||||
|
||||
export * from "./font-size";
|
||||
|
||||
export default FontSize;
|
||||
265
packages/editor/src/extensions/image/component.tsx
Normal file
265
packages/editor/src/extensions/image/component.tsx
Normal file
@@ -0,0 +1,265 @@
|
||||
import { Box, Flex, Image, ImageProps, Text } from "rebass";
|
||||
import { NodeViewWrapper, NodeViewProps, FloatingMenu } from "@tiptap/react";
|
||||
import {
|
||||
ImageAlignmentOptions,
|
||||
ImageAttributes,
|
||||
ImageSizeOptions,
|
||||
} from "./image";
|
||||
import { ThemeConfig } from "@notesnook/theme/dist/theme/types";
|
||||
import { ThemeProvider } from "emotion-theming";
|
||||
import { Theme, useTheme } from "@notesnook/theme";
|
||||
import { Resizable } from "re-resizable";
|
||||
import { ToolButton } from "../../toolbar/components/tool-button";
|
||||
import { findToolById, ToolId } from "../../toolbar/tools";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { MenuPresenter } from "../../components/menu/menu";
|
||||
import { Popup } from "../../toolbar/components/popup";
|
||||
import { Toggle } from "../../components/toggle";
|
||||
import { Input } from "@rebass/forms";
|
||||
|
||||
export function ImageComponent(props: ImageProps & NodeViewProps) {
|
||||
const { src, alt, title, width, height, align, float } = props.node
|
||||
.attrs as ImageAttributes & ImageAlignmentOptions;
|
||||
|
||||
const { editor, updateAttributes } = props;
|
||||
const imageRef = useRef<HTMLImageElement>();
|
||||
const isActive = editor.isActive("image", { src });
|
||||
const [isToolbarVisible, setIsToolbarVisible] = useState<boolean>();
|
||||
const theme = editor.storage.theme as Theme;
|
||||
|
||||
useEffect(() => {
|
||||
setIsToolbarVisible(isActive);
|
||||
}, [isActive]);
|
||||
|
||||
return (
|
||||
<NodeViewWrapper>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Box
|
||||
sx={{
|
||||
display: float ? "block" : "flex",
|
||||
justifyContent: float
|
||||
? "stretch"
|
||||
: align === "center"
|
||||
? "center"
|
||||
: align === "left"
|
||||
? "start"
|
||||
: "end",
|
||||
}}
|
||||
>
|
||||
<Resizable
|
||||
style={{
|
||||
float: float ? (align === "left" ? "left" : "right") : "none",
|
||||
}}
|
||||
size={{
|
||||
height: height || "auto",
|
||||
width: width || "auto",
|
||||
}}
|
||||
maxWidth="100%"
|
||||
onResizeStop={(e, direction, ref, d) => {
|
||||
updateAttributes({
|
||||
width: ref.clientWidth,
|
||||
height: ref.clientHeight,
|
||||
});
|
||||
}}
|
||||
lockAspectRatio={true}
|
||||
>
|
||||
<Flex sx={{ position: "relative", justifyContent: "end" }}>
|
||||
{isToolbarVisible && (
|
||||
<ImageToolbar
|
||||
editor={editor}
|
||||
float={float}
|
||||
align={align}
|
||||
height={height || 0}
|
||||
width={width || 0}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
<Image
|
||||
ref={imageRef}
|
||||
src={src}
|
||||
alt={alt}
|
||||
title={title}
|
||||
width={"100%"}
|
||||
height={"100%"}
|
||||
sx={{
|
||||
border: isActive
|
||||
? "2px solid var(--primary)"
|
||||
: "2px solid transparent",
|
||||
borderRadius: "default",
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
</Resizable>
|
||||
</Box>
|
||||
</ThemeProvider>
|
||||
</NodeViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
type ImageToolbarProps = ImageAlignmentOptions &
|
||||
Required<ImageSizeOptions> & {
|
||||
editor: Editor;
|
||||
};
|
||||
|
||||
function ImageToolbar(props: ImageToolbarProps) {
|
||||
const { editor, float, height, width } = props;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const onSizeChange = useCallback(
|
||||
(newWidth?: number, newHeight?: number) => {
|
||||
const size: ImageSizeOptions = newWidth
|
||||
? {
|
||||
width: newWidth,
|
||||
height: newWidth * (height / width),
|
||||
}
|
||||
: newHeight
|
||||
? {
|
||||
width: newHeight * (width / height),
|
||||
height: newHeight,
|
||||
}
|
||||
: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
|
||||
editor.chain().setImageSize(size).run();
|
||||
},
|
||||
[width, height]
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
position: "absolute",
|
||||
top: -40,
|
||||
mb: 2,
|
||||
zIndex: 9999,
|
||||
alignItems: "end",
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
bg: "background",
|
||||
boxShadow: "menu",
|
||||
flexWrap: "nowrap",
|
||||
borderRadius: "default",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
className="toolbar-group"
|
||||
sx={{
|
||||
pr: 1,
|
||||
mr: 1,
|
||||
borderRight: "1px solid var(--border)",
|
||||
":last-of-type": { mr: 0, pr: 0, borderRight: "none" },
|
||||
}}
|
||||
>
|
||||
<ToolButton
|
||||
toggled={false}
|
||||
title="Align left"
|
||||
id="alignLeft"
|
||||
icon="alignLeft"
|
||||
onClick={() =>
|
||||
editor.chain().focus().setImageAlignment({ align: "left" }).run()
|
||||
}
|
||||
/>
|
||||
{float ? null : (
|
||||
<ToolButton
|
||||
toggled={false}
|
||||
title="Align center"
|
||||
id="alignCenter"
|
||||
icon="alignCenter"
|
||||
onClick={() =>
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.setImageAlignment({ align: "center" })
|
||||
.run()
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<ToolButton
|
||||
toggled={false}
|
||||
title="Align right"
|
||||
id="alignRight"
|
||||
icon="alignRight"
|
||||
onClick={() =>
|
||||
editor.chain().focus().setImageAlignment({ align: "right" }).run()
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
className="toolbar-group"
|
||||
sx={{
|
||||
pr: 1,
|
||||
mr: 1,
|
||||
borderRight: "1px solid var(--border)",
|
||||
":last-of-type": { mr: 0, pr: 0, borderRight: "none" },
|
||||
}}
|
||||
>
|
||||
<ToolButton
|
||||
toggled={isOpen}
|
||||
title="Image properties"
|
||||
id="imageProperties"
|
||||
icon="more"
|
||||
onClick={() => setIsOpen((s) => !s)}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{isOpen && (
|
||||
<Popup
|
||||
title="Image properties"
|
||||
action={{
|
||||
icon: "close",
|
||||
onClick: () => {
|
||||
setIsOpen(false);
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Flex sx={{ width: 200, flexDirection: "column", p: 1 }}>
|
||||
<Flex
|
||||
sx={{ justifyContent: "space-between", alignItems: "center" }}
|
||||
>
|
||||
<Text variant={"body"}>Floating?</Text>
|
||||
<Toggle
|
||||
checked={float}
|
||||
onClick={() =>
|
||||
editor
|
||||
.chain()
|
||||
.setImageAlignment({ float: !float, align: "left" })
|
||||
.run()
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex sx={{ alignItems: "center", mt: 2 }}>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Width"
|
||||
value={width}
|
||||
sx={{
|
||||
mr: 2,
|
||||
p: 1,
|
||||
fontSize: "body",
|
||||
}}
|
||||
onChange={(e) => onSizeChange(e.target.valueAsNumber)}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Height"
|
||||
value={height}
|
||||
sx={{ p: 1, fontSize: "body" }}
|
||||
onChange={(e) =>
|
||||
onSizeChange(undefined, e.target.valueAsNumber)
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Popup>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user