Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Editor Core Packaging and Restructuring #2358

Merged
merged 59 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
0887b69
initialized tiptap component with common tailwind config
Palanikannan1437 Sep 8, 2023
b841df6
added common tailwind config to web
Palanikannan1437 Sep 8, 2023
e9e6f43
merge develop into packaging-tiptap
Palanikannan1437 Sep 19, 2023
8e76809
abstracted upload and delete functions
Palanikannan1437 Sep 19, 2023
35ffb85
removed tiptap pro extension
Palanikannan1437 Sep 19, 2023
e358487
fixed types
Palanikannan1437 Sep 19, 2023
46c7614
Merge branch 'develop' into packaging-tiptap
Palanikannan1437 Sep 19, 2023
7ef1745
removed old tailwind config and fixed plane package imports
Palanikannan1437 Sep 20, 2023
3b9c29c
exported tiptap editor with and without ref
Palanikannan1437 Sep 20, 2023
28697e3
updated package name to @plane/editor
Palanikannan1437 Sep 20, 2023
8e71ce0
finally fixed import errors
Palanikannan1437 Sep 20, 2023
5f8a0c3
Merge branch 'develop' into packaging-tiptap
Palanikannan1437 Sep 20, 2023
448d433
added turbo dependency for tiptap
Palanikannan1437 Sep 21, 2023
f0e246c
reverted back types and fixed tailwind
Palanikannan1437 Sep 22, 2023
fa01dfc
migrated all components to use the common package
Palanikannan1437 Sep 22, 2023
36fd719
removed old tiptap dependency
Palanikannan1437 Sep 22, 2023
0f9aae6
Merge branch 'develop' into packaging-tiptap
Palanikannan1437 Sep 22, 2023
9079fa4
improved dev experience to build the tiptap package before starting d…
Palanikannan1437 Sep 22, 2023
cbb1c18
resolved lock life and missing deps
Palanikannan1437 Sep 22, 2023
bb13f35
fixed dependency issue with react type resolution
Palanikannan1437 Sep 22, 2023
4981c3d
chore: updated pulls build CI for using turbo builds
henit-chobisa Sep 22, 2023
063f4c7
comment editor basic version added
Palanikannan1437 Sep 25, 2023
d639a01
new structure of editor components
Palanikannan1437 Sep 27, 2023
4298b05
refactored editor to not require workspace slug
Palanikannan1437 Sep 28, 2023
efcc7f2
added seperation of extensions and props
Palanikannan1437 Sep 28, 2023
a754300
Merge branch 'develop' into comment-editor
Palanikannan1437 Sep 28, 2023
da86f1a
refactoring to LiteTextEditor and RichTextEditor
Palanikannan1437 Sep 30, 2023
b5228bb
fixed global css issue with highlight js
Palanikannan1437 Oct 2, 2023
3d87a56
refactoring tiptap to core/lite/rich text editor
Palanikannan1437 Oct 2, 2023
de07f63
read only editor support added
Palanikannan1437 Oct 2, 2023
51e2815
replaced all read-only instances
Palanikannan1437 Oct 2, 2023
2c804c8
trimming html at start and end of content added
Palanikannan1437 Oct 2, 2023
b479718
onSubmit on enterkey captured
Palanikannan1437 Oct 2, 2023
857fa18
removed absolute imports from editor/core package
Palanikannan1437 Oct 3, 2023
0080880
removed absolute imports from lite-text-editor
Palanikannan1437 Oct 3, 2023
95e5a30
removed absolute imports from rich-text-editor
Palanikannan1437 Oct 3, 2023
f408eb3
fixed dependencies in editor package
Palanikannan1437 Oct 3, 2023
fc8284d
fixed tailwind config for editor
Palanikannan1437 Oct 3, 2023
ff29c1c
Enter key behaviour added for Comments
Palanikannan1437 Oct 3, 2023
99618e9
fixed modal form issue
Palanikannan1437 Oct 3, 2023
95439fb
added comment editor with fixed menu
Palanikannan1437 Oct 3, 2023
18c9e64
added support for range commands
Palanikannan1437 Oct 3, 2023
2fd9198
modified turbo config for build pipeline of space and web projects
Palanikannan1437 Oct 3, 2023
696a2e9
fixed shift enter behavior for lists
Palanikannan1437 Oct 4, 2023
a9d197c
removed extra margin from access specifiers
Palanikannan1437 Oct 4, 2023
0cf5ad6
Merge branch 'develop' into comment-editor
Palanikannan1437 Oct 4, 2023
a6b0ef2
removed tiptap instance from web
Palanikannan1437 Oct 4, 2023
cfadb5a
fixed bugs returning empty editor boxes
Palanikannan1437 Oct 4, 2023
37d5e83
fixed toggle Underline behvaiour
Palanikannan1437 Oct 5, 2023
6cb9f73
updated bubble menu to use core package's utilities
Palanikannan1437 Oct 9, 2023
8552ef2
added editor/core readme and fixed imports
Palanikannan1437 Oct 9, 2023
d9c3407
fixed ts issues with link plugin
Palanikannan1437 Oct 10, 2023
ede27b7
added usage of common dependance for slash commands
Palanikannan1437 Oct 10, 2023
3ea7ab3
completed core package's documentation
Palanikannan1437 Oct 10, 2023
67fd3e2
fixed tsconfig by removing path aliases
Palanikannan1437 Oct 10, 2023
8ba39dc
Completed readme for rich-text-editor
Palanikannan1437 Oct 10, 2023
2ce9f3b
Added rich text editor documentation
Palanikannan1437 Oct 10, 2023
b6f1cb7
changed readme title of core package
Palanikannan1437 Oct 10, 2023
59d2ce6
Merge branch 'develop' into comment-editor
Palanikannan1437 Oct 12, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/build-test-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,13 @@ jobs:
- name: Build Plane's Main App
if: steps.changed-files.outputs.web_any_changed == 'true'
run: |
cd web
yarn
yarn build
yarn build --filter=web

- name: Build Plane's Deploy App
if: steps.changed-files.outputs.deploy_any_changed == 'true'
run: |
cd space
yarn
yarn build
yarn build --filter=space


4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,7 @@ pnpm-lock.yaml
pnpm-workspace.yaml

.npmrc


## packages
dist
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
"workspaces": [
"web",
"space",
"packages/*"
"packages/editor/*",
"packages/eslint-config-custom",
"packages/tailwind-config-custom",
"packages/tsconfig",
"packages/ui"
],
"scripts": {
"build": "turbo run build",
Expand All @@ -25,5 +29,8 @@
"tailwindcss": "^3.3.3",
"turbo": "latest"
},
"resolutions": {
"@types/react": "18.2.0"
},
"packageManager": "yarn@1.22.19"
}
112 changes: 112 additions & 0 deletions packages/editor/core/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# @plane/editor-core

## Description

The `@plane/editor-core` package serves as the foundation for our editor system. It provides the base functionality for our other editor packages, but it will not be used directly in any of the projects but only for extending other editors.

## Utilities

We provide a wide range of utilities for extending the core itself.

1. Merging classes and custom styling
2. Adding new extensions
3. Adding custom props
4. Base menu items, and their commands

This allows for extensive customization and flexibility in the Editors created using our `editor-core` package.

### Here's a detailed overview of what's exported

1. useEditor - A hook that you can use to extend the Plane editor.

| Prop | Type | Description |
| --- | --- | --- |
| `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features |
| `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object |
| `uploadFile` | `(file: File) => Promise<string>` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. |
| `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise<any>` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. |
| `value` | `html string` | The initial content of the editor. |
| `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. |
| `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. |
| `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. |
| `setShouldShowAlert` | `(showAlert: boolean) => void` | This function is used to show or hide an alert in case of content not being "saved". |
| `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component |

2. useReadOnlyEditor - A hook that can be used to extend a Read Only instance of the core editor.

| Prop | Type | Description |
| --- | --- | --- |
| `value` | `string` | The initial content of the editor. |
| `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component |
| `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features |
| `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object |

3. Items and Commands - H1, H2, H3, task list, quote, code block, etc's methods.

4. UI Wrappers

- `EditorContainer` - Wrap your Editor Container with this to apply base classes and styles.
- `EditorContentWrapper` - Use this to get Editor's Content and base menus.

5. Extending with Custom Styles

```ts
const customEditorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName });
```

## Core features

- **Content Trimming**: The Editor’s content is now automatically trimmed of empty line breaks from the start and end before submitting it to the backend. This ensures cleaner, more consistent data.
- **Value Cleaning**: The Editor’s value is cleaned at the editor core level, eliminating the need for additional validation before sending from our app. This results in cleaner code and less potential for errors.
- **Turbo Pipeline**: Added a turbo pipeline for both dev and build tasks for projects depending on the editor package.

```json
"web#develop": {
"cache": false,
"persistent": true,
"dependsOn": [
"@plane/lite-text-editor#build",
"@plane/rich-text-editor#build"
]
},
"space#develop": {
"cache": false,
"persistent": true,
"dependsOn": [
"@plane/lite-text-editor#build",
"@plane/rich-text-editor#build"
]
},
"web#build": {
"cache": true,
"dependsOn": [
"@plane/lite-text-editor#build",
"@plane/rich-text-editor#build"
]
},
"space#build": {
"cache": true,
"dependsOn": [
"@plane/lite-text-editor#build",
"@plane/rich-text-editor#build"
]
},

```

## Base extensions included

- BulletList
- OrderedList
- Blockquote
- Code
- Gapcursor
- Link
- Image
- Basic Marks
- Underline
- TextStyle
- Color
- TaskList
- Markdown
- Table
76 changes: 76 additions & 0 deletions packages/editor/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "@plane/editor-core",
"version": "0.0.1",
"description": "Core Editor that powers Plane",
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"files": [
"dist/**/*"
],
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"module": "./dist/index.mjs"
}
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"check-types": "tsc --noEmit"
},
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "18.2.0",
"next": "12.3.2",
"next-themes": "^0.2.1"
},
"dependencies": {
"@blueprintjs/popover2": "^2.0.10",
"@tiptap/core": "^2.1.7",
"@tiptap/extension-color": "^2.1.11",
"@tiptap/extension-image": "^2.1.7",
"@tiptap/extension-link": "^2.1.7",
"@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/react": "^2.1.7",
"@tiptap/starter-kit": "^2.1.10",
"@types/react": "^18.2.5",
"@types/react-dom": "18.0.11",
"@types/node": "18.15.3",
"class-variance-authority": "^0.7.0",
"clsx": "^1.2.1",
"eslint": "8.36.0",
"eslint-config-next": "13.2.4",
"eventsource-parser": "^0.1.0",
"lucide-react": "^0.244.0",
"react-markdown": "^8.0.7",
"tailwind-merge": "^1.14.0",
"tippy.js": "^6.3.7",
"tiptap-markdown": "^0.8.2",
"use-debounce": "^9.0.4"
},
"devDependencies": {
"eslint": "^7.32.0",
"postcss": "^8.4.29",
"tailwind-config-custom": "*",
"tsconfig": "*",
"tsup": "^7.2.0",
"typescript": "4.9.5"
},
"keywords": [
"editor",
"rich-text",
"markdown",
"nextjs",
"react"
]
}
9 changes: 9 additions & 0 deletions packages/editor/core/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// If you want to use other PostCSS plugins, see the following:
// https://tailwindcss.com/docs/using-with-preprocessors

module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
19 changes: 19 additions & 0 deletions packages/editor/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// styles
// import "./styles/tailwind.css";
// import "./styles/editor.css";

// utils
export * from "./lib/utils";
export { startImageUpload } from "./ui/plugins/upload-image";

// components
export { EditorContainer } from "./ui/components/editor-container";
export { EditorContentWrapper } from "./ui/components/editor-content";

// hooks
export { useEditor } from "./ui/hooks/useEditor";
export { useReadOnlyEditor } from "./ui/hooks/useReadOnlyEditor";

// helper items
export * from "./ui/menus/menu-items";
export * from "./lib/editor-commands";
91 changes: 91 additions & 0 deletions packages/editor/core/src/lib/editor-commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Editor, Range } from "@tiptap/core";
import { UploadImage } from "../types/upload-image";
import { startImageUpload } from "../ui/plugins/upload-image";

export const toggleHeadingOne = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
else editor.chain().focus().toggleHeading({ level: 1 }).run()
};

export const toggleHeadingTwo = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
else editor.chain().focus().toggleHeading({ level: 2 }).run()
};

export const toggleHeadingThree = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
else editor.chain().focus().toggleHeading({ level: 3 }).run()
};

export const toggleBold = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleBold().run();
else editor.chain().focus().toggleBold().run();
};

export const toggleItalic = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleItalic().run();
else editor.chain().focus().toggleItalic().run();
};

export const toggleUnderline = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleUnderline().run();
else editor.chain().focus().toggleUnderline().run();
};

export const toggleCode = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleCode().run();
else editor.chain().focus().toggleCode().run();
};
export const toggleOrderedList = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleOrderedList().run();
else editor.chain().focus().toggleOrderedList().run();
};

export const toggleBulletList = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleBulletList().run();
else editor.chain().focus().toggleBulletList().run();
};

export const toggleTaskList = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleTaskList().run();
else editor.chain().focus().toggleTaskList().run()
};

export const toggleStrike = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleStrike().run();
else editor.chain().focus().toggleStrike().run();
};

export const toggleBlockquote = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run();
else editor.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run();
};

export const insertTableCommand = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
else editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
};

export const unsetLinkEditor = (editor: Editor) => {
editor.chain().focus().unsetLink().run();
};

export const setLinkEditor = (editor: Editor, url: string) => {
editor.chain().focus().setLink({ href: url }).run();
};

export const insertImageCommand = (editor: Editor, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).run();
const input = document.createElement("input");
input.type = "file";
input.accept = "image/*";
input.onchange = async () => {
if (input.files?.length) {
const file = input.files[0];
const pos = editor.view.state.selection.from;
startImageUpload(file, editor.view, pos, uploadFile, setIsSubmitting);
}
};
input.click();
};

Loading
Loading