red-axe / am-editor

A rich text editor that supports collaborative editing and allows for the free use of front-end common libraries such as React and Vue to extend and define plugins.
https://editor.aomao.com
MIT License
937 stars 197 forks source link

How to set up the editor in vanilla TypeScript #317

Closed hussain-attari closed 1 year ago

hussain-attari commented 1 year ago

I am trying to set up the editor in my laravel 10 app and trying to initialize it using vanilla TypeScript. Not sure if what I am doing is correct or if I am doing it in the correct manner. Its just a short in the dark.

// editor.ts

import Engine, { PluginEntry } from '@aomao/engine';
import Bold from '@aomao/plugin-bold';
import Italic from '@aomao/plugin-italic';
import Underline from '@aomao/plugin-underline';
import Strikethrough from '@aomao/plugin-strikethrough';
import Heading from '@aomao/plugin-heading';
import Quote from '@aomao/plugin-quote';
import OrderedList from '@aomao/plugin-orderedlist';
import UnorderedList from '@aomao/plugin-unorderedlist';
import CodeBlock from '@aomao/plugin-codeblock';
import Table from '@aomao/plugin-table';
import Image from '@aomao/plugin-image';
import Video from '@aomao/plugin-video';
import Link from '@aomao/plugin-link';
import Mention from '@aomao/plugin-mention';
import Tasklist from '@aomao/plugin-tasklist';
import Undo from '@aomao/plugin-undo';
import Redo from '@aomao/plugin-redo';

const plugins: PluginEntry[] = [
  Bold,
  Italic,
  Underline,
  Strikethrough,
  Heading,
  Quote,
  OrderedList,
  UnorderedList,
  CodeBlock,
  Table,
  Image,
  Video,
  Link,
  Mention,
  Tasklist,
  Undo,
  Redo,
];

const toolbar = [
  'bold',
  'italic',
  'underline',
  'strikethrough',
  '|',
  'heading',
  'quote',
  'orderedlist',
  'unorderedlist',
  'codeblock',
  'table',
  '|',
  'image',
  'video',
  'link',
  'mention',
  'emoji',
  'tasklist',
  '|',
  'undo',
  'redo',
];

export const initializeEditor = (container: HTMLElement) => {
  const editor = new Engine({
    // container,
    plugins,
    toolbar,
  });

  editor.render();

  return editor;
};

Then on my blade file I do this code

<script type="module">
  import { initializeEditor } from '/path/to/editor.ts';

  const editorContainer = document.getElementById('editor');
  const editor = initializeEditor(editorContainer);
</script>

Can anyone help me set up the editor on Laravel 10.

big-camel commented 1 year ago

https://codesandbox.io/s/eloquent-darwin-czlts9?file=/src/index.js

hussain-attari commented 1 year ago

Thank you for the quick response.

I like this way of the the code flow. This will help me control the styling with tailwind and also add only those buttons that are required in the editor

I like your default editor and toolbar styling. Is there a way that I can use the default styles and sprinkle a few styles of my own through tailwind css that would either overwrite the existing style or add to the existing style.

Also could you show an example for a toolbar button with a dropdown say adding a table or changing the font style. .

Furthermore any work around for codeblock and link? And any options to add emoji?

big-camel commented 1 year ago

Sorry, the toolbar, codeblock, and link plugins now use React for UI interaction. However, apart from the toolbar, there is less utilization of React for UI interaction in the other plugins. For example, the dropdown menu for selecting code languages in the codeblock plugin uses React. I suggest copying the source code and making modifications for better customization.

As for emoji support, there is currently no ready-made plugin available. However, I have updated an example at https://codesandbox.io/s/eloquent-darwin-czlts9?file=/src/emoji/index.js.

hussain-attari commented 1 year ago

Can you please show me how to get this look and style of the editor.

https://editor.aomao.com/

big-camel commented 1 year ago

https://editor.aomao.com/demos_md_inline.553dd688.chunk.css https://github.com/red-axe/am-editor/blob/master/packages/toolbar/src/index.css

hussain-attari commented 1 year ago

Hi,

I had multiple errors when I tried to compile my editor.ts TypeScript file with the codesandbox code.

I made the relevant changes to the editor.ts code however I am now getting errors on these two am-editor files that i installed through npm

// Remaining errors

Errors  Files
1] 1  node_modules/@aomao/engine/dist/plugin/index.d.ts:9 - Refering to this line "import { BlockInterface, InlineInterface, MarkInterface } from 'src';"

The error is
"Cannot find module 'src' or its corresponding type declarations."

2] 1  node_modules/@aomao/plugin-image/dist/types.d.ts:3 - Refering to this line "import PhotoSwipe from 'photoswipe';"

The error is 
"Could not find a declaration file for module 'photoswipe'. '{my-folder}/node_modules/photoswipe/dist/photoswipe.js' implicitly has an 'any' type. Try `npm i --save-dev @types/photoswipe` if it exists or add a new declaration (.d.ts) file containing `declare module 'photoswipe';`"

Ran the command `npm i --save-dev @types/photoswipe` but it didn't work

// Resolved Errors I also had these errors on these lines

Removed them by npm installing the respective files.

// Modified codesandbox code

import Engine from "@aomao/engine";
import Bold from "@aomao/plugin-bold";
import Italic from "@aomao/plugin-italic";
import Underline from "@aomao/plugin-underline";
import Strikethrough from "@aomao/plugin-strikethrough";
import Heading from "@aomao/plugin-heading";
import Quote from "@aomao/plugin-quote";
import OrderedList from "@aomao/plugin-orderedlist";
import UnorderedList from "@aomao/plugin-unorderedlist";
import FontSize from "@aomao/plugin-fontsize";
import FontFamily from "@aomao/plugin-fontfamily";
import Table, { TableComponent } from "@aomao/plugin-table";
import Image, { ImageComponent } from "@aomao/plugin-image";
import Video, { VideoComponent } from "@aomao/plugin-video";
import Mention from "@aomao/plugin-mention";
import Tasklist from "@aomao/plugin-tasklist";
import Undo from "@aomao/plugin-undo";
import Redo from "@aomao/plugin-redo";

const plugins = [
    Bold,
    Italic,
    Underline,
    Strikethrough,
    Heading,
    Quote,
    OrderedList,
    UnorderedList,
    Table,
    Image,
    Video,
    Mention,
    Tasklist,
    Undo,
    Redo,
    FontFamily,
    FontSize,
];

const cards = [TableComponent, ImageComponent, VideoComponent];

export const initializeEditor = (container: HTMLElement) => {
    const editor = new Engine(container, {
        plugins,
        cards,
    });

    editor.setHtml("<p>test</p>");

    return editor;
};

const editorContainer = document.getElementById("app");

if (editorContainer) {
    const editor = initializeEditor(editorContainer);

    const toolbar = document.getElementById("toolbar");

    if (toolbar) {
        const toolsMap = new Map();
        toolbar.childNodes.forEach((child) => {
            if (!(child instanceof HTMLElement)) return;
            const command = child.getAttribute("command");
            if (command) {
                const defaultArgs = JSON.parse(
                    child.getAttribute("defaultArgs") ?? "[]"
                );
                if (child.nodeName === "SELECT") {
                    child.addEventListener("change", (e) => {
                        const selectElement = e.target as HTMLSelectElement;
                        editor.command.execute(command, selectElement.value);
                    });
                } else if (child.nodeName === "BUTTON") {
                    child.addEventListener("click", () => {
                        editor.command.execute(command, ...defaultArgs);
                    });
                } else if (child.nodeName === "DIV") {
                    const items = child.querySelectorAll("[defaultArgs]");
                    items.forEach((item) => {
                        item.addEventListener("click", (e) => {
                            const defaultArgs = item.getAttribute("defaultArgs");
                            editor.command.execute(command, defaultArgs);
                        });
                    });
                }
                toolsMap.set(command, child);
            }
        });

        editor.on("select", () => {
            for (const [key, element] of toolsMap) {
                const state = editor.command.queryState(key);
                if (element.nodeName === "BUTTON") {
                    element.setAttribute(
                        "style",
                        `color: ${state ? "red" : "black"}`
                    );
                } else if (element.nodeName === "SELECT") {
                    const selectElement = element as HTMLSelectElement;
                    selectElement.value = state ?? "14px";
                }
            }
        });
    }
}

Please advise on how to resolve the remaining errors

big-camel commented 1 year ago

https://codesandbox.io/s/boring-chaum-zsnxgy?file=/index.html

hussain-attari commented 1 year ago

Still getting this error on compiling the TypeScript.

Cannot find module 'src' or its corresponding type declarations.

The error is in this file "resource": "{my_folder}/node_modules/@aomao/engine/dist/plugin/index.d.ts"

and on this line import { BlockInterface, InlineInterface, MarkInterface } from 'src';

big-camel commented 1 year ago

Still getting this error on compiling the TypeScript.

Cannot find module 'src' or its corresponding type declarations.

The error is in this file "resource": "{my_folder}/node_modules/@aomao/engine/dist/plugin/index.d.ts"

and on this line import { BlockInterface, InlineInterface, MarkInterface } from 'src';

@aomao/engine@2.10.21

hussain-attari commented 1 year ago

This resolves the error and set ups the editor correctly. Thanks a ton.

hussain-attari commented 1 year ago

Help me set up the front end css as well. This is the current html code I added some basic Tailwind styles to the editor div

<div id="toolbar" class="editor-toolbar" style="display: flex; gap: 4px;">
    <button command="bold">Bold</button>
    <button command="table" defaultArgs="[3, 3]">Table</button>
    <select command="fontsize">
      <option value="14px">14px</option>
      <option value="18px">18px</option>
      <option value="20px">20px</option>
      <option value="24px">24px</option>
    </select>
    <div style="display: flex; gap: 2px;" command="emoji">
      <span defaultArgs="😀">😀</span>
      <span defaultArgs="😄">😄</span>
      <span defaultArgs="😁">😁</span>
      <span defaultArgs="😆">😆</span>
    </div>
</div>

I know you have provided the css files before but how do I set it up?

Your default style that you have on https://editor.aomao.com/ is perfectly fine.

All I would want is to add the following things on my end 1] the toolbar position on each editor depending on where it is being used. 2] the buttons on each editor 3] the size of the editor 4] add a dark class to the editor.

Also, how do I set up the tooltip language to English?