[refactor] Editor code refactoring (#3194)

* removed relative imports from editor core

* Update issue widget file paths and imports to use kebab case instead of camel case, to align with coding conventions and improve consistency.

* Update Tiptap core and extensions versions to 2.1.13 and Tiptap React version to 2.1.13. Update Tiptap table imports to use the new location in package @tiptap/pm/tables. Update AlertLabel component to use the new type definition for LucideIcon.

* updated lock file

* removed default exports from editor/core

* fixed injecting css into the core package itself

* seperated css code to have single source of origin wrt to the package

* removed default imports from document editor

* all instances using index as key while mapping fixed

* Update Lite Text Editor package.json to remove @plane/editor-types as a dependency.

Update Lite Text Editor index.ts to update the import of IMentionSuggestion and IMentionHighlight from @plane/editor-types to @plane/editor-core.

Update Lite Text Editor ui/index.tsx to update the import of UploadImage, DeleteImage, IMentionSuggestion, and RestoreImage from @plane/editor-types to @plane/editor-core.

Update Lite Text Editor ui/menus/fixed-menu/index.tsx to update the import of UploadImage from @plane/editor-types to @plane/editor-core.

Update turbo.json to remove @plane/editor-types#build as a dependency for @plane/lite-text-editor#build, @plane/rich-text-editor#build, and @plane/document-editor#build.

* Remove deprecated import and adjust tippy.js usage in the slash-commands.tsx file of the editor extensions package.

* Update dependencies in `rich-text-editor/package.json`, remove `@plane/editor-types` and add `@plane/editor-core` in `rich-text-editor/src/index.ts`, and update imports in `rich-text-editor/src/ui/extensions/index.tsx` and `rich-text-editor/src/ui/index.tsx` to use `@plane/editor-core` instead of `@plane/editor-types`.

* Update package.json dependencies and add new types for image deletion, upload, restore, mention highlight, mention suggestion, and slash command item.

* Update import statements in various files to use the new package "@plane/editor-core" instead of "@plane/editor-types".

* fixed document editor to follow conventions

* Refactor imports in the Rich Text Editor package to use relative paths instead of absolute paths.

- Updated imports in `index.ts`, `ui/index.tsx`, and `ui/menus/bubble-menu/index.tsx` to use relative paths.
- Updated `tsconfig.json` to include the `baseUrl` compiler option and adjust the `include` and `exclude` paths.

* Refactor Lite Text Editor code to use relative import paths instead of absolute import paths.

* Added LucideIconType to the exports in index.ts for use in other files.
Created a new file lucide-icon.ts which contains the type LucideIconType.
Updated the icon type in HeadingOneItem in menu-items/index.tsx to use LucideIconType.
Updated the Icon type in AlertLabel in alert-label.tsx to use LucideIconType.
Updated the Icon type in VerticalDropdownItemProps in vertical-dropdown-menu.tsx to use LucideIconType.
Updated the Icon type in BubbleMenuItem in fixed-menu/index.tsx to use LucideIconType.
Deleted the file tooltip.tsx since it is no longer used.
Updated the Icon type in BubbleMenuItem in bubble-menu/index.tsx to use LucideIconType.

* ♻️ refactor: simplify rendering logic in slash-commands.tsx

The rendering logic in the file "slash-commands.tsx" has been simplified. Previously, the code used inline positioning for the popup, but it has now been removed. Instead of appending the popup to the document body, it is now appended to the element with the ID "tiptap-container". The "flip" option has also been removed. These changes have improved the readability and maintainability of the code.

* fixed build errors caused due to core's internal imports

* regression: fixed pages not saving issue and not duplicating with proper content issue

* build: Update @tiptap dependencies

Updated the @tiptap dependencies in the package.json files of `document-editor`, `extensions`, and `rich-text-editor` packages to version 2.1.13.

* 🚑 fix: Correct appendTo selector in slash-commands.tsx

Update the `appendTo` function call in `slash-commands.tsx` to use the correct selector `#editor-container` instead of `#tiptap-container`. This ensures that the component is appended to the appropriate container in the editor extension.

Note: The commit message assumes that the change is a fix for an issue or error. If it's not a fix, please provide more context so that an appropriate commit type can be determined.
This commit is contained in:
M. Palanikannan 2023-12-21 16:01:38 +05:30 committed by sriram veeraghanta
parent aceee7d2e2
commit 0b1efb173f
115 changed files with 513 additions and 1548 deletions

View File

@ -28,28 +28,22 @@
"react-dom": "18.2.0"
},
"dependencies": {
"@plane/editor-types": "*",
"@tiptap/core": "^2.1.7",
"@tiptap/core": "^2.1.13",
"@tiptap/extension-blockquote": "^2.1.13",
"@tiptap/extension-code-block-lowlight": "^2.1.12",
"@tiptap/extension-color": "^2.1.11",
"@tiptap/extension-image": "^2.1.7",
"@tiptap/extension-link": "^2.1.7",
"@tiptap/extension-list-item": "^2.1.12",
"@tiptap/extension-mention": "^2.1.12",
"@tiptap/extension-table": "^2.1.6",
"@tiptap/extension-table-cell": "^2.1.6",
"@tiptap/extension-table-header": "^2.1.6",
"@tiptap/extension-table-row": "^2.1.6",
"@tiptap/extension-task-item": "^2.1.7",
"@tiptap/extension-task-list": "^2.1.7",
"@tiptap/extension-text-style": "^2.1.11",
"@tiptap/extension-underline": "^2.1.7",
"@tiptap/pm": "^2.1.7",
"@tiptap/prosemirror-tables": "^1.1.4",
"@tiptap/react": "^2.1.7",
"@tiptap/starter-kit": "^2.1.10",
"@tiptap/suggestion": "^2.0.4",
"@tiptap/extension-code-block-lowlight": "^2.1.13",
"@tiptap/extension-color": "^2.1.13",
"@tiptap/extension-image": "^2.1.13",
"@tiptap/extension-link": "^2.1.13",
"@tiptap/extension-list-item": "^2.1.13",
"@tiptap/extension-mention": "^2.1.13",
"@tiptap/extension-task-item": "^2.1.13",
"@tiptap/extension-task-list": "^2.1.13",
"@tiptap/extension-text-style": "^2.1.13",
"@tiptap/extension-underline": "^2.1.13",
"@tiptap/pm": "^2.1.13",
"@tiptap/react": "^2.1.13",
"@tiptap/starter-kit": "^2.1.13",
"@tiptap/suggestion": "^2.0.13",
"class-variance-authority": "^0.7.0",
"clsx": "^1.2.1",
"highlight.js": "^11.8.0",

View File

@ -1,10 +1,13 @@
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
import { useImperativeHandle, useRef, MutableRefObject } from "react";
import { CoreEditorProps } from "../props";
import { CoreEditorExtensions } from "../extensions";
import { CoreEditorProps } from "src/ui/props";
import { CoreEditorExtensions } from "src/ui/extensions";
import { EditorProps } from "@tiptap/pm/view";
import { getTrimmedHTML } from "../../lib/utils";
import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types";
import { getTrimmedHTML } from "src/lib/utils";
import { DeleteImage } from "src/types/delete-image";
import { IMentionSuggestion } from "src/types/mention-suggestion";
import { RestoreImage } from "src/types/restore-image";
import { UploadImage } from "src/types/upload-image";
interface CustomEditorProps {
uploadFile: UploadImage;

View File

@ -1,9 +1,9 @@
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
import { useImperativeHandle, useRef, MutableRefObject } from "react";
import { CoreReadOnlyEditorExtensions } from "../read-only/extensions";
import { CoreReadOnlyEditorProps } from "../read-only/props";
import { CoreReadOnlyEditorExtensions } from "src/ui/read-only/extensions";
import { CoreReadOnlyEditorProps } from "src/ui/read-only/props";
import { EditorProps } from "@tiptap/pm/view";
import { IMentionSuggestion } from "@plane/editor-types";
import { IMentionSuggestion } from "src/types/mention-suggestion";
interface CustomReadOnlyEditorProps {
value: string;

View File

@ -1,23 +1,32 @@
// styles
// import "./styles/tailwind.css";
// import "./styles/editor.css";
import "./styles/github-dark.css";
import "src/styles/editor.css";
import "src/styles/table.css";
import "src/styles/github-dark.css";
export { isCellSelection } from "./ui/extensions/table/table/utilities/is-cell-selection";
export { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection";
// utils
export * from "./lib/utils";
export * from "./ui/extensions/table/table";
export { startImageUpload } from "./ui/plugins/upload-image";
export * from "src/lib/utils";
export * from "src/ui/extensions/table/table";
export { startImageUpload } from "src/ui/plugins/upload-image";
// components
export { EditorContainer } from "./ui/components/editor-container";
export { EditorContentWrapper } from "./ui/components/editor-content";
export { EditorContainer } from "src/ui/components/editor-container";
export { EditorContentWrapper } from "src/ui/components/editor-content";
// hooks
export { useEditor } from "./ui/hooks/use-editor";
export { useReadOnlyEditor } from "./ui/hooks/use-read-only-editor";
export { useEditor } from "src/hooks/use-editor";
export { useReadOnlyEditor } from "src/hooks/use-read-only-editor";
// helper items
export * from "./ui/menus/menu-items";
export * from "./lib/editor-commands";
export * from "src/ui/menus/menu-items";
export * from "src/lib/editor-commands";
// types
export type { DeleteImage } from "src/types/delete-image";
export type { UploadImage } from "src/types/upload-image";
export type { RestoreImage } from "src/types/restore-image";
export type { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion";
export type { ISlashCommandItem, CommandProps } from "src/types/slash-commands-suggestion";
export type { LucideIconType } from "src/types/lucide-icon";

View File

@ -1,7 +1,7 @@
import { UploadImage } from "@plane/editor-types";
import { Editor, Range } from "@tiptap/core";
import { startImageUpload } from "../ui/plugins/upload-image";
import { findTableAncestor } from "./utils";
import { startImageUpload } from "src/ui/plugins/upload-image";
import { findTableAncestor } from "src/lib/utils";
import { UploadImage } from "src/types/upload-image";
export const toggleHeadingOne = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();

View File

@ -6,6 +6,12 @@
height: 0;
}
/* block quotes */
.ProseMirror blockquote p::before,
.ProseMirror blockquote p::after {
display: none;
}
.ProseMirror .is-empty::before {
content: attr(data-placeholder);
float: left;
@ -15,7 +21,6 @@
}
/* Custom image styles */
.ProseMirror img {
transition: filter 0.1s ease-in-out;
@ -53,11 +58,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
background-color: rgb(var(--color-background-100));
margin: 0;
cursor: pointer;
width: 1.2rem;
height: 1.2rem;
width: 0.8rem;
height: 0.8rem;
position: relative;
border: 2px solid rgb(var(--color-text-100));
margin-right: 0.3rem;
border: 1.5px solid rgb(var(--color-text-100));
margin-right: 0.2rem;
margin-top: 0.15rem;
display: grid;
place-content: center;
@ -71,8 +77,8 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
&::before {
content: "";
width: 0.65em;
height: 0.65em;
width: 0.5em;
height: 0.5em;
transform: scale(0);
transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em;
@ -229,3 +235,34 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
.ProseMirror table * .is-empty::before {
opacity: 0;
}
.ProseMirror pre {
background: rgba(var(--color-background-80));
border-radius: 0.5rem;
color: rgba(var(--color-text-100));
font-family: "JetBrainsMono", monospace;
padding: 0.75rem 1rem;
}
.ProseMirror pre code {
background: none;
color: inherit;
font-size: 0.8rem;
padding: 0;
}
div[data-type="horizontalRule"] {
line-height: 0;
padding: 0.25rem 0;
margin-top: 0;
margin-bottom: 0;
& > div {
border-bottom: 1px solid rgb(var(--color-text-100));
}
}
/* image resizer */
.moveable-control-box {
z-index: 10 !important;
}

View File

@ -0,0 +1,3 @@
import { Smile } from "lucide-react";
export type LucideIconType = typeof Smile;

View File

@ -1,6 +1,6 @@
import { Editor, EditorContent } from "@tiptap/react";
import { ReactNode } from "react";
import { ImageResizer } from "../extensions/image/image-resize";
import { ImageResizer } from "src/ui/extensions/image/image-resize";
interface EditorContentProps {
editor: Editor | null;

View File

@ -1,7 +1,7 @@
import { getNodeAtPosition } from "@tiptap/core";
import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos";
import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
export const getNextListDepth = (typeOrName: string, state: EditorState) => {
const listItemPos = findListItemPos(typeOrName, state);

View File

@ -1,8 +1,8 @@
import { Editor, isAtStartOfNode, isNodeActive } from "@tiptap/core";
import { Node } from "@tiptap/pm/model";
import { findListItemPos } from "./find-list-item-pos";
import { hasListBefore } from "./has-list-before";
import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { hasListBefore } from "src/ui/extensions/custom-list-keymap/list-helpers/has-list-before";
export const handleBackspace = (editor: Editor, name: string, parentListTypes: string[]) => {
// this is required to still handle the undo handling

View File

@ -1,7 +1,7 @@
import { Editor, isAtEndOfNode, isNodeActive } from "@tiptap/core";
import { nextListIsDeeper } from "./next-list-is-deeper";
import { nextListIsHigher } from "./next-list-is-higher";
import { nextListIsDeeper } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper";
import { nextListIsHigher } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher";
export const handleDelete = (editor: Editor, name: string) => {
// if the cursor is not inside the current node type

View File

@ -1,7 +1,7 @@
import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos";
import { getNextListDepth } from "./get-next-list-depth";
import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth";
export const nextListIsDeeper = (typeOrName: string, state: EditorState) => {
const listDepth = getNextListDepth(typeOrName, state);

View File

@ -1,7 +1,7 @@
import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos";
import { getNextListDepth } from "./get-next-list-depth";
import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth";
export const nextListIsHigher = (typeOrName: string, state: EditorState) => {
const listDepth = getNextListDepth(typeOrName, state);

View File

@ -1,6 +1,6 @@
import { Extension } from "@tiptap/core";
import { handleBackspace, handleDelete } from "./list-helpers";
import { handleBackspace, handleDelete } from "src/ui/extensions/custom-list-keymap/list-helpers";
export type ListKeymapOptions = {
listTypes: Array<{

View File

@ -22,7 +22,7 @@ declare module "@tiptap/core" {
}
}
export default Node.create<HorizontalRuleOptions>({
export const HorizontalRule = Node.create<HorizontalRuleOptions>({
name: "horizontalRule",
addOptions() {

View File

@ -1,9 +1,10 @@
import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state";
import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import UploadImagesPlugin from "../../plugins/upload-image";
import { UploadImagesPlugin } from "src/ui/plugins/upload-image";
import ImageExt from "@tiptap/extension-image";
import { onNodeDeleted, onNodeRestored } from "../../plugins/delete-image";
import { DeleteImage, RestoreImage } from "@plane/editor-types";
import { onNodeDeleted, onNodeRestored } from "src/ui/plugins/delete-image";
import { DeleteImage } from "src/types/delete-image";
import { RestoreImage } from "src/types/restore-image";
interface ImageNode extends ProseMirrorNode {
attrs: {
@ -15,7 +16,7 @@ interface ImageNode extends ProseMirrorNode {
const deleteKey = new PluginKey("delete-image");
const IMAGE_NODE_TYPE = "image";
const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) =>
export const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) =>
ImageExt.extend({
addProseMirrorPlugins() {
return [
@ -130,5 +131,3 @@ const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, can
};
},
});
export default ImageExtension;

View File

@ -1,6 +1,6 @@
import Image from "@tiptap/extension-image";
const ReadOnlyImageExtension = Image.extend({
export const ReadOnlyImageExtension = Image.extend({
addAttributes() {
return {
...this.parent?.(),
@ -13,5 +13,3 @@ const ReadOnlyImageExtension = Image.extend({
};
},
});
export default ReadOnlyImageExtension;

View File

@ -7,22 +7,25 @@ import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list";
import { Markdown } from "tiptap-markdown";
import TableHeader from "./table/table-header/table-header";
import Table from "./table/table";
import TableCell from "./table/table-cell/table-cell";
import TableRow from "./table/table-row/table-row";
import HorizontalRule from "./horizontal-rule";
import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import { Table } from "src/ui/extensions/table/table";
import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
import { TableRow } from "src/ui/extensions/table/table-row/table-row";
import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import ImageExtension from "./image";
import { ImageExtension } from "src/ui/extensions/image";
import { isValidHttpUrl } from "../../lib/utils";
import { Mentions } from "../mentions";
import { isValidHttpUrl } from "src/lib/utils";
import { Mentions } from "src/ui/mentions";
import { CustomKeymap } from "./keymap";
import { CustomCodeBlock } from "./code";
import { CustomQuoteExtension } from "./quote";
import { ListKeymap } from "./custom-list-keymap";
import { IMentionSuggestion, DeleteImage, RestoreImage } from "@plane/editor-types";
import { CustomKeymap } from "src/ui/extensions/keymap";
import { CustomCodeBlock } from "src/ui/extensions/code";
import { CustomQuoteExtension } from "src/ui/extensions/quote";
import { ListKeymap } from "src/ui/extensions/custom-list-keymap";
import { DeleteImage } from "src/types/delete-image";
import { IMentionSuggestion } from "src/types/mention-suggestion";
import { RestoreImage } from "src/types/restore-image";
export const CoreEditorExtensions = (
mentionConfig: {

View File

@ -1 +1 @@
export { default as default } from "./table-cell";
export { TableCell } from "./table-cell";

View File

@ -4,7 +4,7 @@ export interface TableCellOptions {
HTMLAttributes: Record<string, any>;
}
export default Node.create<TableCellOptions>({
export const TableCell = Node.create<TableCellOptions>({
name: "tableCell",
addOptions() {

View File

@ -1 +1 @@
export { default as default } from "./table-header";
export { TableHeader } from "./table-header";

View File

@ -3,7 +3,8 @@ import { mergeAttributes, Node } from "@tiptap/core";
export interface TableHeaderOptions {
HTMLAttributes: Record<string, any>;
}
export default Node.create<TableHeaderOptions>({
export const TableHeader = Node.create<TableHeaderOptions>({
name: "tableHeader",
addOptions() {

View File

@ -1 +1 @@
export { default as default } from "./table-row";
export { TableRow } from "./table-row";

View File

@ -4,7 +4,7 @@ export interface TableRowOptions {
HTMLAttributes: Record<string, any>;
}
export default Node.create<TableRowOptions>({
export const TableRow = Node.create<TableRowOptions>({
name: "tableRow",
addOptions() {

View File

@ -1,4 +1,4 @@
const icons = {
export const icons = {
colorPicker: `<svg xmlns="http://www.w3.org/2000/svg" length="24" viewBox="0 0 24 24" style="transform: ;msFilter:;"><path fill="rgb(var(--color-text-300))" d="M20 14c-.092.064-2 2.083-2 3.5 0 1.494.949 2.448 2 2.5.906.044 2-.891 2-2.5 0-1.5-1.908-3.436-2-3.5zM9.586 20c.378.378.88.586 1.414.586s1.036-.208 1.414-.586l7-7-.707-.707L11 4.586 8.707 2.293 7.293 3.707 9.586 6 4 11.586c-.378.378-.586.88-.586 1.414s.208 1.036.586 1.414L9.586 20zM11 7.414 16.586 13H5.414L11 7.414z"></path></svg>`,
deleteColumn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M12 3c.552 0 1 .448 1 1v8c.835-.628 1.874-1 3-1 2.761 0 5 2.239 5 5s-2.239 5-5 5c-1.032 0-1.99-.313-2.787-.848L13 20c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zm-1 2H7v14h4V5zm8 10h-6v2h6v-2z"/></svg>`,
deleteRow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M20 5c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1 .628.835 1 1.874 1 3 0 2.761-2.239 5-5 5s-5-2.239-5-5c0-1.126.372-2.165 1-3H4c-.552 0-1-.448-1-1V6c0-.552.448-1 1-1h16zm-7 10v2h6v-2h-6zm6-8H5v4h14V7z"/></svg>`,
@ -47,5 +47,3 @@ const icons = {
</svg>
`,
};
export default icons;

View File

@ -1 +1 @@
export { default as default } from "./table";
export { Table } from "./table";

View File

@ -4,9 +4,9 @@ import { Decoration, NodeView } from "@tiptap/pm/view";
import tippy, { Instance, Props } from "tippy.js";
import { Editor } from "@tiptap/core";
import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/prosemirror-tables";
import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/pm/tables";
import icons from "./icons";
import { icons } from "src/ui/extensions/table/table/icons";
export function updateColumns(
node: ProseMirrorNode,

View File

@ -19,12 +19,12 @@ import {
tableEditing,
toggleHeader,
toggleHeaderCell,
} from "@tiptap/prosemirror-tables";
} from "@tiptap/pm/tables";
import { tableControls } from "./table-controls";
import { TableView } from "./table-view";
import { createTable } from "./utilities/create-table";
import { deleteTableWhenAllCellsSelected } from "./utilities/delete-table-when-all-cells-selected";
import { tableControls } from "src/ui/extensions/table/table/table-controls";
import { TableView } from "src/ui/extensions/table/table/table-view";
import { createTable } from "src/ui/extensions/table/table/utilities/create-table";
import { deleteTableWhenAllCellsSelected } from "src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected";
export interface TableOptions {
HTMLAttributes: Record<string, any>;
@ -72,7 +72,7 @@ declare module "@tiptap/core" {
}
}
export default Node.create({
export const Table = Node.create({
name: "table",
addOptions() {

View File

@ -1,7 +1,7 @@
import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model";
import { createCell } from "./create-cell";
import { getTableNodeTypes } from "./get-table-node-types";
import { createCell } from "src/ui/extensions/table/table/utilities/create-cell";
import { getTableNodeTypes } from "src/ui/extensions/table/table/utilities/get-table-node-types";
export function createTable(
schema: Schema,

View File

@ -1,6 +1,6 @@
import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core";
import { isCellSelection } from "./is-cell-selection";
import { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection";
export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => {
const { selection } = editor.state;

View File

@ -1,4 +1,4 @@
import { CellSelection } from "@tiptap/prosemirror-tables";
import { CellSelection } from "@tiptap/pm/tables";
export function isCellSelection(value: unknown): value is CellSelection {
return value instanceof CellSelection;

View File

@ -1,8 +1,8 @@
import { Mention, MentionOptions } from "@tiptap/extension-mention";
import { mergeAttributes } from "@tiptap/core";
import { ReactNodeViewRenderer } from "@tiptap/react";
import mentionNodeView from "./mentionNodeView";
import { IMentionHighlight } from "@plane/editor-types";
import { MentionNodeView } from "src/ui/mentions/mention-node-view";
import { IMentionHighlight } from "src/types/mention-suggestion";
export interface CustomMentionOptions extends MentionOptions {
mentionHighlights: IMentionHighlight[];
@ -31,7 +31,7 @@ export const CustomMention = Mention.extend<CustomMentionOptions>({
},
addNodeView() {
return ReactNodeViewRenderer(mentionNodeView);
return ReactNodeViewRenderer(MentionNodeView);
},
parseHTML() {

View File

@ -1,8 +1,8 @@
// @ts-nocheck
import suggestion from "./suggestion";
import { CustomMention } from "./custom";
import { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types";
import { Suggestion } from "src/ui/mentions/suggestion";
import { CustomMention } from "src/ui/mentions/custom";
import { IMentionHighlight } from "src/types/mention-suggestion";
export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighlights: IMentionHighlight[], readonly) =>
CustomMention.configure({
@ -11,5 +11,5 @@ export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighli
},
readonly: readonly,
mentionHighlights: mentionHighlights,
suggestion: suggestion(mentionSuggestions),
suggestion: Suggestion(mentionSuggestions),
});

View File

@ -1,6 +1,6 @@
import { IMentionSuggestion } from "@plane/editor-types";
import { Editor } from "@tiptap/react";
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { IMentionSuggestion } from "src/types/mention-suggestion";
interface MentionListProps {
items: IMentionSuggestion[];
@ -9,7 +9,7 @@ interface MentionListProps {
}
// eslint-disable-next-line react/display-name
const MentionList = forwardRef((props: MentionListProps, ref) => {
export const MentionList = forwardRef((props: MentionListProps, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = (index: number) => {
@ -98,5 +98,3 @@ const MentionList = forwardRef((props: MentionListProps, ref) => {
});
MentionList.displayName = "MentionList";
export default MentionList;

View File

@ -1,12 +1,12 @@
/* eslint-disable react/display-name */
// @ts-nocheck
import { NodeViewWrapper } from "@tiptap/react";
import { cn } from "../../lib/utils";
import { cn } from "src/lib/utils";
import { useRouter } from "next/router";
import { IMentionHighlight } from "@plane/editor-types";
import { IMentionHighlight } from "src/types/mention-suggestion";
// eslint-disable-next-line import/no-anonymous-default-export
export default (props) => {
export const MentionNodeView = (props) => {
const router = useRouter();
const highlights = props.extension.options.mentionHighlights as IMentionHighlight[];

View File

@ -2,10 +2,10 @@ import { ReactRenderer } from "@tiptap/react";
import { Editor } from "@tiptap/core";
import tippy from "tippy.js";
import MentionList from "./MentionList";
import { IMentionSuggestion } from "@plane/editor-types";
import { MentionList } from "src/ui/mentions/mention-list";
import { IMentionSuggestion } from "src/types/mention-suggestion";
const Suggestion = (suggestions: IMentionSuggestion[]) => ({
export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
items: ({ query }: { query: string }) =>
suggestions.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5),
render: () => {
@ -55,5 +55,3 @@ const Suggestion = (suggestions: IMentionSuggestion[]) => ({
};
},
});
export default Suggestion;

View File

@ -30,14 +30,15 @@ import {
toggleStrike,
toggleTaskList,
toggleUnderline,
} from "../../../lib/editor-commands";
import { UploadImage } from "@plane/editor-types";
} from "src/lib/editor-commands";
import { LucideIconType } from "src/types/lucide-icon";
import { UploadImage } from "src/types/upload-image";
export interface EditorMenuItem {
name: string;
isActive: () => boolean;
command: () => void;
icon: typeof BoldIcon;
icon: LucideIconType;
}
export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({

View File

@ -1,6 +1,7 @@
import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state";
import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import { DeleteImage, RestoreImage } from "@plane/editor-types";
import { DeleteImage } from "src/types/delete-image";
import { RestoreImage } from "src/types/restore-image";
const deleteKey = new PluginKey("delete-image");
const IMAGE_NODE_TYPE = "image";
@ -12,7 +13,7 @@ interface ImageNode extends ProseMirrorNode {
};
}
const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin =>
export const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin =>
new Plugin({
key: deleteKey,
appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => {
@ -53,8 +54,6 @@ const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin =>
},
});
export default TrackImageDeletionPlugin;
export async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise<void> {
try {
const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1);

View File

@ -1,10 +1,10 @@
import { UploadImage } from "@plane/editor-types";
import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view";
import { UploadImage } from "src/types/upload-image";
const uploadKey = new PluginKey("upload-image");
const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
export const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
new Plugin({
key: uploadKey,
state: {
@ -60,8 +60,6 @@ const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
},
});
export default UploadImagesPlugin;
function findPlaceholder(state: EditorState, id: {}) {
const decos = uploadKey.getState(state);
const found = decos.find(undefined, undefined, (spec: { id: number | undefined }) => spec.id == id);

View File

@ -1,7 +1,7 @@
import { UploadImage } from "@plane/editor-types";
import { EditorProps } from "@tiptap/pm/view";
import { findTableAncestor } from "../lib/utils";
import { startImageUpload } from "./plugins/upload-image";
import { findTableAncestor } from "src/lib/utils";
import { UploadImage } from "src/types/upload-image";
import { startImageUpload } from "src/ui/plugins/upload-image";
export function CoreEditorProps(
uploadFile: UploadImage,

View File

@ -8,15 +8,16 @@ import TaskList from "@tiptap/extension-task-list";
import { Markdown } from "tiptap-markdown";
import Gapcursor from "@tiptap/extension-gapcursor";
import TableHeader from "../extensions/table/table-header/table-header";
import Table from "../extensions/table/table";
import TableCell from "../extensions/table/table-cell/table-cell";
import TableRow from "../extensions/table/table-row/table-row";
import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import { Table } from "src/ui/extensions/table/table";
import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
import { TableRow } from "src/ui/extensions/table/table-row/table-row";
import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import ReadOnlyImageExtension from "../extensions/image/read-only-image";
import { isValidHttpUrl } from "../../lib/utils";
import { Mentions } from "../mentions";
import { IMentionSuggestion } from "@plane/editor-types";
import { ReadOnlyImageExtension } from "src/ui/extensions/image/read-only-image";
import { isValidHttpUrl } from "src/lib/utils";
import { Mentions } from "src/ui/mentions";
import { IMentionSuggestion } from "src/types/mention-suggestion";
export const CoreReadOnlyEditorExtensions = (mentionConfig: {
mentionSuggestions: IMentionSuggestion[];
@ -71,6 +72,7 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
class: "rounded-lg border border-custom-border-300",
},
}),
HorizontalRule,
TiptapUnderline,
TextStyle,
Color,

View File

@ -1,5 +1,15 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
"include": [
"src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
}

View File

@ -30,12 +30,11 @@
"dependencies": {
"@plane/editor-core": "*",
"@plane/editor-extensions": "*",
"@plane/editor-types": "*",
"@plane/ui": "*",
"@tiptap/core": "^2.1.7",
"@tiptap/extension-placeholder": "^2.1.11",
"@tiptap/pm": "^2.1.12",
"@tiptap/suggestion": "^2.1.12",
"@tiptap/core": "^2.1.13",
"@tiptap/extension-placeholder": "^2.1.13",
"@tiptap/pm": "^2.1.13",
"@tiptap/suggestion": "^2.1.13",
"eslint": "8.36.0",
"eslint-config-next": "13.2.4",
"react-popper": "^2.3.0",

View File

@ -1,6 +1,5 @@
import { Editor } from "@tiptap/react";
import { useState } from "react";
import { IMarking } from "..";
import { IMarking } from "src/types/editor-types";
export const useEditorMarkings = () => {
const [markings, setMarkings] = useState<IMarking[]>([]);

View File

@ -1,3 +1,3 @@
export { DocumentEditor, DocumentEditorWithRef } from "./ui";
export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "./ui/readonly";
export { FixedMenu } from "./ui/menu/fixed-menu";
export { DocumentEditor, DocumentEditorWithRef } from "src/ui";
export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "src/ui/readonly";
export { FixedMenu } from "src/ui/menu/fixed-menu";

View File

@ -5,3 +5,9 @@ export interface DocumentDetails {
last_updated_by: string;
last_updated_at: Date;
}
export interface IMarking {
type: "heading";
level: number;
text: string;
sequence: number;
}

View File

@ -1,12 +1,11 @@
import { Icon } from "lucide-react";
import { LucideIconType } from "@plane/editor-core";
interface IAlertLabelProps {
Icon?: Icon;
Icon?: LucideIconType;
backgroundColor: string;
textColor?: string;
label: string;
}
export const AlertLabel = (props: IAlertLabelProps) => {
const { Icon, backgroundColor, textColor, label } = props;

View File

@ -1,7 +1,7 @@
import { HeadingComp, HeadingThreeComp, SubheadingComp } from "./heading-component";
import { IMarking } from "..";
import { HeadingComp, HeadingThreeComp, SubheadingComp } from "src/ui/components/heading-component";
import { IMarking } from "src/types/editor-types";
import { Editor } from "@tiptap/react";
import { scrollSummary } from "../utils/editor-summary-utils";
import { scrollSummary } from "src/utils/editor-summary-utils";
interface ContentBrowserProps {
editor: Editor;

View File

@ -1,13 +1,12 @@
import { Editor } from "@tiptap/react";
import { Archive, RefreshCw, Lock } from "lucide-react";
import { IMarking } from "..";
import { FixedMenu } from "../menu";
import { UploadImage } from "@plane/editor-types";
import { DocumentDetails } from "../types/editor-types";
import { AlertLabel } from "./alert-label";
import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "./vertical-dropdown-menu";
import { SummaryPopover } from "./summary-popover";
import { InfoPopover } from "./info-popover";
import { IMarking, DocumentDetails } from "src/types/editor-types";
import { FixedMenu } from "src/ui/menu";
import { UploadImage } from "@plane/editor-core";
import { AlertLabel } from "src/ui/components/alert-label";
import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu";
import { SummaryPopover } from "src/ui/components/summary-popover";
import { InfoPopover } from "src/ui/components/info-popover";
interface IEditorHeader {
editor: Editor;

View File

@ -2,7 +2,7 @@ import { useState } from "react";
import { usePopper } from "react-popper";
import { Calendar, History, Info } from "lucide-react";
// types
import { DocumentDetails } from "../types/editor-types";
import { DocumentDetails } from "src/types/editor-types";
type Props = {
documentDetails: DocumentDetails;

View File

@ -1,7 +1,7 @@
import { EditorContainer, EditorContentWrapper } from "@plane/editor-core";
import { Editor } from "@tiptap/react";
import { useState } from "react";
import { DocumentDetails } from "../types/editor-types";
import { DocumentDetails } from "src/types/editor-types";
type IPageRenderer = {
documentDetails: DocumentDetails;

View File

@ -3,9 +3,9 @@ import { Editor } from "@tiptap/react";
import { usePopper } from "react-popper";
import { List } from "lucide-react";
// components
import { ContentBrowser } from "./content-browser";
import { ContentBrowser } from "src/ui/components/content-browser";
// types
import { IMarking } from "..";
import { IMarking } from "src/types/editor-types";
type Props = {
editor: Editor;

View File

@ -1,6 +1,6 @@
import { Editor } from "@tiptap/react";
import { IMarking } from "..";
import { ContentBrowser } from "./content-browser";
import { IMarking } from "src/types/editor-types";
import { ContentBrowser } from "src/ui/components/content-browser";
interface ISummarySideBarProps {
editor: Editor;
@ -8,14 +8,12 @@ interface ISummarySideBarProps {
sidePeekVisible: boolean;
}
export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => {
return (
<div
className={`h-full transform overflow-hidden p-5 transition-all duration-200 ${
sidePeekVisible ? "translate-x-0" : "-translate-x-full"
}`}
>
<ContentBrowser editor={editor} markings={markings} />
</div>
);
};
export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => (
<div
className={`h-full transform overflow-hidden p-5 transition-all duration-200 ${
sidePeekVisible ? "translate-x-0" : "-translate-x-full"
}`}
>
<ContentBrowser editor={editor} markings={markings} />
</div>
);

View File

@ -1,5 +1,6 @@
import { Button, CustomMenu } from "@plane/ui";
import { ChevronUp, Icon, MoreVertical } from "lucide-react";
import { LucideIconType } from "@plane/editor-core";
import { CustomMenu } from "@plane/ui";
import { MoreVertical } from "lucide-react";
type TMenuItems =
| "archive_page"
@ -14,7 +15,7 @@ type TMenuItems =
export interface IVerticalDropdownItemProps {
key: number;
type: TMenuItems;
Icon: Icon;
Icon: LucideIconType;
label: string;
action: () => Promise<void> | void;
}
@ -23,27 +24,23 @@ export interface IVerticalDropdownMenuProps {
items: IVerticalDropdownItemProps[];
}
const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => {
return (
<CustomMenu.MenuItem onClick={action} className="flex items-center gap-2">
<Icon className="h-3 w-3" />
<div className="text-custom-text-300">{label}</div>
</CustomMenu.MenuItem>
);
};
const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => (
<CustomMenu.MenuItem onClick={action} className="flex items-center gap-2">
<Icon className="h-3 w-3" />
<div className="text-custom-text-300">{label}</div>
</CustomMenu.MenuItem>
);
export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => {
return (
<CustomMenu
maxHeight={"md"}
className={"h-4.5 mt-1"}
placement={"bottom-start"}
optionsClassName={"border-custom-border border-r border-solid transition-all duration-200 ease-in-out "}
customButton={<MoreVertical size={14} />}
>
{items.map((item, index) => (
<VerticalDropdownItem key={index} type={item.type} Icon={item.Icon} label={item.label} action={item.action} />
))}
</CustomMenu>
);
};
export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => (
<CustomMenu
maxHeight={"md"}
className={"h-4.5 mt-1"}
placement={"bottom-start"}
optionsClassName={"border-custom-border border-r border-solid transition-all duration-200 ease-in-out "}
customButton={<MoreVertical size={14} />}
>
{items.map((item) => (
<VerticalDropdownItem key={item.key} type={item.type} Icon={item.Icon} label={item.label} action={item.action} />
))}
</CustomMenu>
);

View File

@ -1,11 +1,11 @@
import Placeholder from "@tiptap/extension-placeholder";
import { IssueWidgetExtension } from "./widgets/IssueEmbedWidget";
import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget";
import { IIssueEmbedConfig } from "./widgets/IssueEmbedWidget/types";
import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
import { SlashCommand, DragAndDrop } from "@plane/editor-extensions";
import { ISlashCommandItem, UploadImage } from "@plane/editor-types";
import { IssueSuggestions } from "./widgets/IssueEmbedSuggestionList";
import { ISlashCommandItem, UploadImage } from "@plane/editor-core";
import { IssueSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list";
import { LayersIcon } from "@plane/ui";
export const DocumentEditorExtensions = (

View File

@ -1,16 +0,0 @@
import { IIssueListSuggestion } from ".";
export const getIssueSuggestionItems = (issueSuggestions: Array<IIssueListSuggestion>) => {
return ({ query }: { query: string }) => {
const search = query.toLowerCase();
const filteredSuggestions = issueSuggestions.filter((item) => {
return (
item.title.toLowerCase().includes(search) ||
item.identifier.toLowerCase().includes(search) ||
item.priority.toLowerCase().includes(search)
);
});
return filteredSuggestions;
};
};

View File

@ -1,7 +1,7 @@
import { Editor, Range } from "@tiptap/react";
import { IssueEmbedSuggestions } from "./issue-suggestion-extension";
import { getIssueSuggestionItems } from "./issue-suggestion-items";
import { IssueListRenderer } from "./issue-suggestion-renderer";
import { IssueEmbedSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-extension";
import { getIssueSuggestionItems } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items";
import { IssueListRenderer } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer";
import { v4 as uuidv4 } from "uuid";
export type CommandProps = {
@ -19,7 +19,7 @@ export interface IIssueListSuggestion {
export const IssueSuggestions = (suggestions: any[]) => {
const mappedSuggestions: IIssueListSuggestion[] = suggestions.map((suggestion): IIssueListSuggestion => {
let transactionId = uuidv4();
const transactionId = uuidv4();
return {
title: suggestion.name,
priority: suggestion.priority.toString(),

View File

@ -0,0 +1,15 @@
import { IIssueListSuggestion } from "src/ui/extensions/widgets/issue-embed-suggestion-list";
export const getIssueSuggestionItems =
(issueSuggestions: Array<IIssueListSuggestion>) =>
({ query }: { query: string }) => {
const search = query.toLowerCase();
const filteredSuggestions = issueSuggestions.filter(
(item) =>
item.title.toLowerCase().includes(search) ||
item.identifier.toLowerCase().includes(search) ||
item.priority.toLowerCase().includes(search)
);
return filteredSuggestions;
};

View File

@ -171,7 +171,7 @@ const IssueSuggestionList = ({
section === currentSection && index === selectedIndex,
}
)}
key={index}
key={item.identifier}
onClick={() => selectItem(index)}
>
<h5 className="whitespace-nowrap text-xs text-custom-text-300">{item.identifier}</h5>

View File

@ -1,5 +1,5 @@
import { IssueWidget } from "./issue-widget-node";
import { IIssueEmbedConfig } from "./types";
import { IssueWidget } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-node";
import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
interface IssueWidgetExtensionProps {
issueEmbedConfig?: IIssueEmbedConfig;

View File

@ -4,7 +4,7 @@ import { NodeViewWrapper } from "@tiptap/react";
import { Avatar, AvatarGroup, Loader, PriorityIcon } from "@plane/ui";
import { Calendar, AlertTriangle } from "lucide-react";
const IssueWidgetCard = (props) => {
export const IssueWidgetCard = (props) => {
const [loading, setLoading] = useState<number>(1);
const [issueDetails, setIssueDetails] = useState();
@ -42,11 +42,9 @@ const IssueWidgetCard = (props) => {
</div>
<div>
<AvatarGroup size="sm">
{issueDetails.assignee_details.map((assignee) => {
return (
<Avatar key={assignee.id} name={assignee.display_name} src={assignee.avatar} className={"m-0"} />
);
})}
{issueDetails.assignee_details.map((assignee) => (
<Avatar key={assignee.id} name={assignee.display_name} src={assignee.avatar} className={"m-0"} />
))}
</AvatarGroup>
</div>
{issueDetails.target_date && (
@ -76,5 +74,3 @@ const IssueWidgetCard = (props) => {
</NodeViewWrapper>
);
};
export default IssueWidgetCard;

View File

@ -1,5 +1,5 @@
import { mergeAttributes, Node } from "@tiptap/core";
import IssueWidgetCard from "./issue-widget-card";
import { IssueWidgetCard } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-card";
import { ReactNodeViewRenderer } from "@tiptap/react";
export const IssueWidget = Node.create({

View File

@ -1,17 +1,16 @@
"use client";
import React, { useState } from "react";
import { getEditorClassNames, useEditor } from "@plane/editor-core";
import { DocumentEditorExtensions } from "./extensions";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "./types/menu-actions";
import { EditorHeader } from "./components/editor-header";
import { useEditorMarkings } from "./hooks/use-editor-markings";
import { SummarySideBar } from "./components/summary-side-bar";
import { DocumentDetails } from "./types/editor-types";
import { PageRenderer } from "./components/page-renderer";
import { getMenuOptions } from "./utils/menu-options";
import { UploadImage, DeleteImage, RestoreImage, getEditorClassNames, useEditor } from "@plane/editor-core";
import { DocumentEditorExtensions } from "src/ui/extensions";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions";
import { EditorHeader } from "src/ui/components/editor-header";
import { useEditorMarkings } from "src/hooks/use-editor-markings";
import { SummarySideBar } from "src/ui/components/summary-side-bar";
import { DocumentDetails } from "src/types/editor-types";
import { PageRenderer } from "src/ui/components/page-renderer";
import { getMenuOptions } from "src/utils/menu-options";
import { useRouter } from "next/router";
import { IEmbedConfig } from "./extensions/widgets/IssueEmbedWidget/types";
import { UploadImage, DeleteImage, RestoreImage } from "@plane/editor-types";
import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
interface IDocumentEditor {
// document info
@ -59,13 +58,6 @@ interface EditorHandle {
setEditorValue: (content: string) => void;
}
export interface IMarking {
type: "heading";
level: number;
text: string;
sequence: number;
}
const DocumentEditor = ({
documentDetails,
onChange,

View File

@ -17,8 +17,8 @@ import {
HeadingThreeItem,
findTableAncestor,
EditorMenuItem,
UploadImage,
} from "@plane/editor-core";
import { UploadImage } from "@plane/editor-types";
export type BubbleMenuItem = EditorMenuItem;

View File

@ -1,15 +1,15 @@
import { getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core";
import { useRouter } from "next/router";
import { useState, forwardRef, useEffect } from "react";
import { EditorHeader } from "../components/editor-header";
import { PageRenderer } from "../components/page-renderer";
import { SummarySideBar } from "../components/summary-side-bar";
import { IssueWidgetExtension } from "../extensions/widgets/IssueEmbedWidget";
import { IEmbedConfig } from "../extensions/widgets/IssueEmbedWidget/types";
import { useEditorMarkings } from "../hooks/use-editor-markings";
import { DocumentDetails } from "../types/editor-types";
import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "../types/menu-actions";
import { getMenuOptions } from "../utils/menu-options";
import { EditorHeader } from "src/ui/components/editor-header";
import { PageRenderer } from "src/ui/components/page-renderer";
import { SummarySideBar } from "src/ui/components/summary-side-bar";
import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget";
import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
import { useEditorMarkings } from "src/hooks/use-editor-markings";
import { DocumentDetails } from "src/types/editor-types";
import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "src/types/menu-actions";
import { getMenuOptions } from "src/utils/menu-options";
interface IDocumentReadOnlyEditor {
value: string;

View File

@ -1,5 +1,5 @@
import { Editor } from "@tiptap/react";
import { IMarking } from "..";
import { IMarking } from "src/types/editor-types";
function findNthH1(editor: Editor, n: number, level: number): number {
let count = 0;

View File

@ -1,19 +1,9 @@
import { Editor } from "@tiptap/react";
import {
Archive,
ArchiveIcon,
ArchiveRestoreIcon,
ClipboardIcon,
Copy,
Link,
Lock,
Unlock,
XCircle,
} from "lucide-react";
import { Archive, ArchiveRestoreIcon, ClipboardIcon, Copy, Link, Lock, Unlock } from "lucide-react";
import { NextRouter } from "next/router";
import { IVerticalDropdownItemProps } from "../components/vertical-dropdown-menu";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "../types/menu-actions";
import { copyMarkdownToClipboard, CopyPageLink } from "./menu-actions";
import { IVerticalDropdownItemProps } from "src/ui/components/vertical-dropdown-menu";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions";
import { copyMarkdownToClipboard, CopyPageLink } from "src/utils/menu-actions";
export interface MenuOptionsProps {
editor: Editor;

View File

@ -1,5 +1,15 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
"include": [
"src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
}

View File

@ -29,11 +29,10 @@
},
"dependencies": {
"@plane/editor-core": "*",
"@plane/editor-types": "*",
"@tiptap/core": "^2.1.7",
"@tiptap/pm": "^2.1.7",
"@tiptap/react": "^2.1.7",
"@tiptap/suggestion": "^2.0.4",
"@tiptap/core": "^2.1.13",
"@tiptap/pm": "^2.1.13",
"@tiptap/react": "^2.1.13",
"@tiptap/suggestion": "^2.1.13",
"eslint": "8.36.0",
"eslint-config-next": "13.2.4",
"lucide-react": "^0.294.0",

View File

@ -3,7 +3,6 @@ import { Editor, Range, Extension } from "@tiptap/core";
import Suggestion from "@tiptap/suggestion";
import { ReactRenderer } from "@tiptap/react";
import tippy from "tippy.js";
import type { UploadImage, ISlashCommandItem, CommandProps } from "@plane/editor-types";
import {
CaseSensitive,
Code2,
@ -19,6 +18,9 @@ import {
Table,
} from "lucide-react";
import {
UploadImage,
ISlashCommandItem,
CommandProps,
cn,
insertTableCommand,
toggleBlockquote,

View File

@ -1,2 +1,4 @@
export { SlashCommand } from "./extensions/slash-commands";
export { DragAndDrop } from "./extensions/drag-drop";
import "src/styles/drag-drop.css";
export { SlashCommand } from "src/extensions/slash-commands";
export { DragAndDrop } from "src/extensions/drag-drop";

View File

@ -0,0 +1,53 @@
.drag-handle {
position: fixed;
opacity: 1;
transition: opacity ease-in 0.2s;
height: 18px;
width: 15px;
display: grid;
place-items: center;
z-index: 10;
cursor: grab;
border-radius: 2px;
background-color: rgb(var(--color-background-90));
}
.drag-handle:hover {
background-color: rgb(var(--color-background-80));
transition: background-color 0.2s;
}
.drag-handle.hidden {
opacity: 0;
pointer-events: none;
}
@media screen and (max-width: 600px) {
.drag-handle {
display: none;
pointer-events: none;
}
}
.drag-handle-container {
height: 15px;
width: 15px;
cursor: grab;
display: grid;
place-items: center;
}
.drag-handle-dots {
height: 100%;
width: 12px;
display: grid;
grid-template-columns: repeat(2, 1fr);
place-items: center;
}
.drag-handle-dot {
height: 2.75px;
width: 3px;
background-color: rgba(var(--color-text-200));
border-radius: 50%;
}

View File

@ -1,5 +1,15 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
"include": [
"src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
}

View File

@ -30,8 +30,7 @@
},
"dependencies": {
"@plane/editor-core": "*",
"@plane/ui": "*",
"@plane/editor-types": "*"
"@plane/ui": "*"
},
"devDependencies": {
"@types/node": "18.15.3",

View File

@ -1,3 +1,3 @@
export { LiteTextEditor, LiteTextEditorWithRef } from "./ui";
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "./ui/read-only";
export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-types";
export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui";
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only";
export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-core";

View File

@ -1,4 +1,4 @@
import { EnterKeyExtension } from "./enter-key-extension";
import { EnterKeyExtension } from "src/ui/extensions/enter-key-extension";
export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [
// EnterKeyExtension(onEnterKeyPress),

View File

@ -1,8 +1,16 @@
import * as React from "react";
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core";
import { FixedMenu } from "./menus/fixed-menu";
import { LiteTextEditorExtensions } from "./extensions";
import { UploadImage, DeleteImage, IMentionSuggestion, RestoreImage } from "@plane/editor-types";
import {
UploadImage,
DeleteImage,
IMentionSuggestion,
RestoreImage,
EditorContainer,
EditorContentWrapper,
getEditorClassNames,
useEditor,
} from "@plane/editor-core";
import { FixedMenu } from "src/ui/menus/fixed-menu";
import { LiteTextEditorExtensions } from "src/ui/extensions";
interface ILiteTextEditor {
value: string;

View File

@ -9,27 +9,21 @@ import {
ImageItem,
isCellSelection,
ItalicItem,
LucideIconType,
NumberedListItem,
QuoteItem,
StrikeThroughItem,
TableItem,
UnderLineItem,
UploadImage,
} from "@plane/editor-core";
import { Tooltip } from "@plane/ui";
import type { SVGProps } from "react";
import { UploadImage } from "@plane/editor-types";
interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
size?: string | number;
absoluteStrokeWidth?: boolean;
}
type LucideIcon = (props: LucideProps) => JSX.Element;
export interface BubbleMenuItem {
name: string;
isActive: () => boolean;
command: () => void;
icon: LucideIcon;
icon: LucideIconType;
}
type EditorBubbleMenuProps = {
@ -127,8 +121,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
<div className="flex w-full items-stretch justify-between gap-2 rounded border-[0.5px] border-custom-border-200 bg-custom-background-90 p-1">
<div className="flex items-stretch">
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 pr-2.5">
{basicTextFormattingItems.map((item, index) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}>
{basicTextFormattingItems.map((item) => (
<Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button
type="button"
onClick={item.command}
@ -150,8 +144,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))}
</div>
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5">
{listFormattingItems.map((item, index) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}>
{listFormattingItems.map((item) => (
<Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button
type="button"
onClick={item.command}
@ -173,8 +167,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))}
</div>
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5">
{userActionItems.map((item, index) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}>
{userActionItems.map((item) => (
<Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button
type="button"
onClick={item.command}
@ -196,8 +190,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))}
</div>
<div className="flex items-stretch gap-0.5 pl-2.5">
{complexItems.map((item, index) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}>
{complexItems.map((item) => (
<Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button
type="button"
onClick={item.command}

View File

@ -1,74 +0,0 @@
import * as React from "react";
// next-themes
import { useTheme } from "next-themes";
// tooltip2
import { Tooltip2 } from "@blueprintjs/popover2";
type Props = {
tooltipHeading?: string;
tooltipContent: string | React.ReactNode;
position?:
| "top"
| "right"
| "bottom"
| "left"
| "auto"
| "auto-end"
| "auto-start"
| "bottom-left"
| "bottom-right"
| "left-bottom"
| "left-top"
| "right-bottom"
| "right-top"
| "top-left"
| "top-right";
children: JSX.Element;
disabled?: boolean;
className?: string;
openDelay?: number;
closeDelay?: number;
};
export const Tooltip: React.FC<Props> = ({
tooltipHeading,
tooltipContent,
position = "top",
children,
disabled = false,
className = "",
openDelay = 200,
closeDelay,
}) => {
const { theme } = useTheme();
return (
<Tooltip2
disabled={disabled}
hoverOpenDelay={openDelay}
hoverCloseDelay={closeDelay}
content={
<div
className={`relative z-50 max-w-xs gap-1 rounded-md p-2 text-xs shadow-md ${
theme === "custom" ? "bg-custom-background-100 text-custom-text-200" : "bg-black text-gray-400"
} overflow-hidden break-words ${className}`}
>
{tooltipHeading && (
<h5 className={`font-medium ${theme === "custom" ? "text-custom-text-100" : "text-white"}`}>
{tooltipHeading}
</h5>
)}
{tooltipContent}
</div>
}
position={position}
renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) =>
React.cloneElement(children, {
ref: eleReference,
...tooltipProps,
...children.props,
})
}
/>
);
};

View File

@ -1,5 +1,15 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
"include": [
"src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
}

View File

@ -31,9 +31,8 @@
"dependencies": {
"@plane/editor-core": "*",
"@plane/editor-extensions": "*",
"@plane/editor-types": "*",
"@tiptap/core": "^2.1.11",
"@tiptap/extension-placeholder": "^2.1.11",
"@tiptap/core": "^2.1.13",
"@tiptap/extension-placeholder": "^2.1.13",
"lucide-react": "^0.294.0"
},
"devDependencies": {

View File

@ -1,4 +1,4 @@
export { RichTextEditor, RichTextEditorWithRef } from "./ui";
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "./ui/read-only";
export type { RichTextEditorProps, IRichTextEditor } from "./ui";
export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types";
export { RichTextEditor, RichTextEditorWithRef } from "src/ui";
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only";
export type { RichTextEditorProps, IRichTextEditor } from "src/ui";
export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-core";

View File

@ -1,7 +1,6 @@
import { SlashCommand } from "@plane/editor-extensions";
import { SlashCommand, DragAndDrop } from "@plane/editor-extensions";
import Placeholder from "@tiptap/extension-placeholder";
import { DragAndDrop } from "@plane/editor-extensions";
import { UploadImage } from "@plane/editor-types";
import { UploadImage } from "@plane/editor-core";
export const RichTextEditorExtensions = (
uploadFile: UploadImage,

View File

@ -1,9 +1,17 @@
"use client";
import * as React from "react";
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core";
import { EditorBubbleMenu } from "./menus/bubble-menu";
import { RichTextEditorExtensions } from "./extensions";
import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types";
import {
DeleteImage,
EditorContainer,
EditorContentWrapper,
getEditorClassNames,
IMentionSuggestion,
RestoreImage,
UploadImage,
useEditor,
} from "@plane/editor-core";
import { EditorBubbleMenu } from "src/ui/menus/bubble-menu";
import { RichTextEditorExtensions } from "src/ui/extensions";
export type IRichTextEditor = {
value: string;

View File

@ -1,15 +1,15 @@
import { BubbleMenu, BubbleMenuProps, isNodeSelection } from "@tiptap/react";
import { FC, useEffect, useState } from "react";
import { BoldIcon } from "lucide-react";
import { NodeSelector } from "./node-selector";
import { LinkSelector } from "./link-selector";
import { NodeSelector } from "src/ui/menus/bubble-menu/node-selector";
import { LinkSelector } from "src/ui/menus/bubble-menu/link-selector";
import {
BoldItem,
cn,
CodeItem,
isCellSelection,
ItalicItem,
LucideIconType,
StrikeThroughItem,
UnderLineItem,
} from "@plane/editor-core";
@ -18,7 +18,7 @@ export interface BubbleMenuItem {
name: string;
isActive: () => boolean;
command: () => void;
icon: typeof BoldIcon;
icon: LucideIconType;
}
type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">;
@ -117,9 +117,9 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props: any) => {
}}
/>
<div className="flex">
{items.map((item, index) => (
{items.map((item) => (
<button
key={index}
key={item.name}
type="button"
onClick={item.command}
className={cn(

View File

@ -56,9 +56,9 @@ export const NodeSelector: FC<NodeSelectorProps> = ({ editor, isOpen, setIsOpen
{isOpen && (
<section className="fixed top-full z-[99999] mt-1 flex w-48 flex-col overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 p-1 shadow-xl animate-in fade-in slide-in-from-top-1">
{items.map((item, index) => (
{items.map((item) => (
<button
key={index}
key={item.name}
type="button"
onClick={() => {
item.command();

View File

@ -1,5 +1,15 @@
{
"extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"],
"exclude": ["dist", "build", "node_modules"]
"include": [
"src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
}

View File

@ -1,4 +0,0 @@
module.exports = {
root: true,
extends: ["custom"],
};

View File

@ -1,6 +0,0 @@
.next
.vercel
.tubro
out/
dis/
build/

Some files were not shown because too many files have changed in this diff Show More