npm package: @nagwa-limited/html-editor
Description: A Typescript & React project that creates a WYSIWYG Rich text/ HTML editor using Slate js.
Latest version: 3.4.12

# Nagwa HTML Editor <!-- omit in toc -->

A Typescript & React project that creates a WYSIWYG Rich text/ HTML editor using Slate js.

## Table of Content: <!-- omit in toc -->

- [1. Getting Started](#1-getting-started)
  - [1.1. Installation](#11-installation)
    - [1.1.1. Using CDN](#111-using-cdn)
    - [1.1.2. Using NPM](#112-using-npm)
  - [1.2. Documentation](#12-documentation)
    - [1.2.1. Component Library API](#121-component-library-api)
    - [1.2.2. Component Library API Explanation](#122-component-library-api-explanation)
    - [1.2.3. Static API Interface](#123-static-api-interface)
    - [1.2.4. Static API Explanation](#124-static-api-explanation)
  - [1.3. Editor Output Samples](#13-editor-output-samples)
  - [1.4. Example Using The API](#14-example-using-the-api)
    - [1.4.1. Using the Static API](#141-using-the-static-api)
    - [1.4.2. Using the Component Library API](#142-using-the-component-library-api)
- [2. Forking Guide](#2-forking-guide)
  - [2.1. Prerequisites](#21-prerequisites)
  - [2.2. Installing](#22-installing)
- [3. Built With](#3-built-with)
- [4. Main Features](#4-main-features)
- [5. Git Style](#5-git-style)
  - [5.1. Message Structure](#51-message-structure)
    - [5.1.1. The Type](#511-the-type)
    - [5.1.2. The Subject](#512-the-subject)
    - [5.1.3. The Body](#513-the-body)
- [React + TypeScript + Vite](#react--typescript--vite)
  - [Expanding the ESLint configuration](#expanding-the-eslint-configuration)

## 1. Getting Started

These instructions will guide you to consume the API provided by the app.

### 1.1. Installation

#### 1.1.1. Using CDN

Following these instructions will integrate the app into your website and will provide a globally defined API to be used.

1. Download the latest version of the app.
2. Link the app's CSS file the head of your HTML File. Example:

   ```HTML
     <head>
         <link href="/static/css/app-min.css" rel="stylesheet"/>
     </head>
   ```

3. Link the app's Javascript file in the body of your HTML File. Example:

   ```HTML
     <body>
         <script src="/static/js/NagwaHTMLEditor.js"></script>
     </body>
   ```

#### 1.1.2. Using NPM

Following these instructions will integrate the app into your website and will provide a react component library that provides the editor react component to be rendered.

```CLI
  npm i nagwa-html-editor
```

and then in your React app import the editor as follows:

```Typescript
import NagwaHTMLEditor from "nagwa-html-editor"
```

### 1.2. Documentation

Here will explain the API provided by our app that can be found under the globally defined namespace `NagwaHTMLEditor`.

#### 1.2.1. Component Library API

A react component is exposed and exported as default that renders the Editor component.

```ts
type Locale = "ar/eg" | "en/eg"

type UploadType = "image" | "audio" | "attachment"
type UploadFunction = (file: File) => Promise<string>
type UploadProps = { storeUrl?: string; uploadFn?: UploadFunction; limit?: number; accept?: string[] }
type UploadConfig = string | UploadFunction | UploadProps

type Feature =
  | "marks" // bold, italic, underlined, and strikethrough marks
  | "color" // text color
  | "scriptEffects" // sub script and super script
  | "alignment"
  | "directions"
  | "undo-redo"
  | PickLiteral<ElementType,  "image" | "audio" | "bulleted-list" |"numbered-list" | "poem" | "table">
  | "math-view"
  | "attach" // Attach files

type MediaType = "image" | "audio" | "attachment"

interface MediaObj {
url: string
}

interface ImageObj extends MediaObj {
alt: string
}

interface AudioObj extends MediaObj {}

interface AttachmentObj extends MediaObj {
name: string
}

interface HTMLEditorProps {
  uniqueKey?: string
  locale?: Locale
  oldValue?: string | Descendant[]
  uploadImage?: UploadConfig
  uploadAudio?: UploadConfig
  uploadAttachment?: UploadFunction | Omit<UploadProps, "storeUrl">
  hideToolbarOnBlur?: boolean
  include?: Feature[]
  exclude?: Feature[]
  onInit?: ((editorAPI: EditorAPI) => void) | (() => void)
  onChange?: ((value: string) => void) | (() => void)
  onAttachmentClick?: (attachment: AttachmentObj, index: number) => void | ((attachment: AttachmentObj) => void) | (() => void) | null
  autoFocus?: boolean
  toolbarStyles?: CSSProperties
  textareaStyles?: CSSProperties
}

export const NagwaHTMLEditor: React.VFC<Props> = () => {...}
export default NagwaHTMLEditor
```

#### 1.2.2. Component Library API Explanation

- `NagwaHTMLEditor`: This is the main component to be used to render an instance of the Editor and keep its state in memory. This component is exported namely and as default so that you can use the `NagwaHTMLEditor` name when importing or use any other name needed in your case. This is a void react component that accepts some props as follows:

  - `uniqueKey`: This key is required and has to be unique because it stores the different editors states in an object with this `uniqueKey`. If it was not provided (not recommended) it will fallback to a **randomly generated key** so that you won't need to add a `uniqueKey` when you need to render only one Editor, if there's more than one please provide a `uniqueKey`.
  - `locale`: The locale of the provided `oldValue` to set the direction of the element according to it. This property is optional and falls back to `"en/eg"` if not provided.
  - `oldValue`: The old HTML value to initiate the app with. This is an optional property, if not provided the app will start with an empty state.
  - `uploadImage`: Can be a function that handles uploading the image inputted by the user, a string url that represents a file storage or hosting service that contains images to be called by ID, or an object containing both properties, and extra. This property is optional, if not provided the feature of inserting images will not be available.
  - `uploadAudio`: Can be a function that handles uploading the audio inputted or recorded by the user, a string url that represents a file storage or hosting service that contains audios to be called by ID, or an object containing both properties, and extra. This property is optional, if not provided the feature of inserting audios will not be available.
  - `uploadAttachment`: Can be a function that handles uploading the file attached by the user or an object containing the function, and extra. This property is optional, if not provided the feature of attaching files will not be available.
  - `hideToolbarOnBlur`: If this property was passed as `true` the toolbar will be hidden until the editor is focused. The default value is `false` which will make the toolbar visible at all times.
  - `include`: An array of feature string to include these features in the editor. By default, all features are included.
  - `exclude`: An array of feature string to exclude from the editor. By default, no feature is excluded. If both `include` and `exclude` arrays are present, the `exclude` array will me omitted, and only the features in the `include` array will be included.
  - `onInit`: A callback function that will fire once the editor is initialized. An optional editorAPI can be expected as an argument to the function.
  - `onChange`:A callback function that will fire with every update of the editor's value. An optional string value (the new editor's value) can be expected as an argument to the function.
  - `onAttachmentClick`: A callback function that will fire when an attachment row is clicked. An optional attachment object and an optional index can be expected as arguments to the function. This property defaults to a function that will download the attachment when clicked. If set to `null`, Nothing will happen when clicking the attachment.
  - `autoFocus`: A boolean that indicates whether or not to focus the editor if it is initialized. Defaults to `false`.
  - `toolbarStyles`: A `CSSProperties` (styles) object that can be passed to apply styles to the toolbar.
  - `textareaStyles`: A `CSSProperties` (styles) object that can be passed to apply styles to the editor's textarea.

Aside from the exported component the API extraction and deletion is implementing the following functions that are namely exported.

```ts
interface EditorAPI {
  editor: CustomEditor // The slate Editor API
  getValue: (includeAttachments = true) => string
  getDeserializedValueWithoutAttachments: () => Descendant[]
  getAttachmentsValue: () => string
  getDeserializedAttachments: () => AttachmentObj
  setValue: (oldValue: string, { locale?: "ar/eg" | "en/eg"; includeAttachments: boolean } = { includeAttachments: true }) => void
  setDeserializedValue: (oldValue: Descendant[], shouldDeleteAttachments = true) => void
  setAttachments: (oldValue: string | AttachmentObj[]) => void
  clear: (shouldDeleteAttachments = true) => void
  readonly isEmpty: boolean
}

function getEditorAPI(uniqueKey: string): EditorAPI // The same Static API interface (See the below section)
function deleteEditorAPI(uniqueKey: string): boolean
```

- `EditorAPI`:
  - `editor`: The slate editor itself
  - `getValue`: This method serializes the current editor value state into the desired HTML output. It takes an optional parameter `includeAttachments`. If set to `true`, the attachments value will be serialized also. It defaults to `true`.
  - `getDeserializedValueWithoutAttachments`: This method returns the current state of the corresponding editor, without the attachments part. The state matches the structure mentioned in the `@types` folder.
  - `getAttachmentsValue`: This method serializes the attachments and returns its `string` value.
  - `getDeserializedAttachments`: This method returns the current state of attachment array. The state matches the structure mentioned in the `@types` folder.
  - `setValue`: This method deserializes the HTML string inputted and sets the editor's state to the deserialized value. It takes an optional options object with the following properties:
    - `includeAttachments`: If set to `true`, the attachments value will be set also, else, the textarea value will be set only, and the attachments will remain the same. It defaults to `true`.
    - `locale`: `"ar/eg"` or `"en/eg"`
  - `setDeserializedValue`: Sets the editor's current value from slates Descendant object array. It takes an optional parameter `shouldDeleteAttachments` that defaults to `true`. If true, will delete current attachments
  - `setAttachments`: Takes an attachments HTML markup string, or an array of attachment object, and sets the attachments.
  - `deleteAttachments`: Deletes current attachments
  - `clear`: This method clears the current editor value state and empties the editable area. It takes an optional parameter `shouldDeleteAttachments` that defaults to `true`. If true, will delete current attachments
  - `isEmpty`: This is a read-only property that tells you if the current state of the editor is empty or not.
- `getEditorAPI`: A function that accesses the store with the `uniqueKey` and returns the corresponding `EditorAPI` for this editor instance. Notice that this `uniqueKey` should be the same one as the one provided for the `NagwaHTMLEditor` component.  
  This function is only namely exported.
- `deleteEditorAPI`: A function that accesses the store with the `uniqueKey` and deletes the corresponding `EditorAPI` for this editor instance. Notice that this `uniqueKey` should be the same one as the one provided for the `NagwaHTMLEditor` component.  
  This function is only namely exported.

#### 1.2.3. Static API Interface

The Static library uses the same API as the component library with some differences.

```ts
type Descendant = CustomElement | CustomText

type StaticHTMLEditorProps = HTMLEditorProps & { containerId: string }

class NagwaHTMLEditor {
  public static init: (config: StaticHTMLEditorProps) => EditorAPI
}
```

#### 1.2.4. Static API Explanation

The static library API uses the same API of the [Component API](#121-component-library-api)'s Interface with few different exported items.

- `NagwaHTMLEditor`:
  - `init`: The main method that initiates the app with the desired config and returns `EditorAPI` object with utility methods.
- `EditorConfig`:
  - `containerId`: The id of the HTML element to contain the app. Note that the element corresponding with the provided id will be replaced with a `div` element with the same provided id. This property is mandatory for the app to run, if not provided the app won't run.

### 1.3. Editor Output Samples

Here are some editor output samples that you can get using the `getValue` method:

- 1 text samples (bold, italic, ... etc.):

  - EN:  
    ![Example 1 Input English Sample](./documentation/assets/images/1.en.png "Example 1 Input English Sample")

    ```HTML
    <p style="text-align: left;"><b>This is Bold.</b></p>
    <p style="text-align: left;"><i>This is Italic.</i></p>
    <p style="text-align: left;"><u>This is Underlined.</u></p>
    <p style="text-align: left;"><span style="color:#e51d74">This is Colored.</span></p>
    <p style="text-align: left;"><i><b>This is Bold Italic.</b></i></p>
    <p style="text-align: left;"><u><b>This is Bold and Underlined.</b></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><b>This is Bold and Colored.</b></span></p>
    <p style="text-align: left;"><u><i>This is Italic and Underlined.</i></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><i>This is Italic and Colored.</i></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u>This is Underlined and Colored.</u></span></p>
    <p style="text-align: left;"><u><i><b>This is Bold, Italic, and Underlined.</b></i></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><i><b>This is Bold, Italic, and Colored</b></i></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><b>This is Bold, Underlined, and Colored.</b></u></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><i>This is Italic, Underlined, and Colored</i></u></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><i><b>This is Bold, Italic, Underlined and Colored.</b></i></u></span></p>
    ```

  - FR:  
    ![Example 1 Input French Sample](./documentation/assets/images/1.fr.png "Example 1 Input French Sample")

    ```HTML
    <p style="text-align: left;"><b>C'est audacieux.</b></p>
    <p style="text-align: left;"><i>C'est en italique.</i></p>
    <p style="text-align: left;"><u>Ceci est souligné.</u></p>
    <p style="text-align: left;"><span style="color:#e51d74">C'est coloré.</span></p>
    <p style="text-align: left;"><i><b>Ceci est en gras italique.</b></i></p>
    <p style="text-align: left;"><u><b>Ceci est gras et souligné.</b></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><b>C'est audacieux et coloré.</b></span></p>
    <p style="text-align: left;"><u><i>Ceci est en italique et souligné.</i></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><i>Ceci est en italique et en couleur.</i></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u>Ceci est souligné et coloré.</u></span></p>
    <p style="text-align: left;"><u><i><b>Ceci est en gras, italique et souligné.</b></i></u></p>
    <p style="text-align: left;"><span style="color:#e51d74"><i><b>Ceci est gras, italique et coloré.</b></i></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><b>Ceci est gras, souligné et coloré.</b></u></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><i>Ceci est en italique, souligné et coloré.</i></u></span></p>
    <p style="text-align: left;"><span style="color:#e51d74"><u><i><b>Ceci est gras, italique, souligné et coloré.</b></i></u></span></p>
    ```

  - AR:  
    ![Example 1 Arabic Input Sample](./documentation/assets/images/1.ar.png "Example 1 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right;"><b>هذا غامق.</b></p>
    <p dir="rtl" style="text-align: right;"><i>هذا مائل.</i></p>
    <p dir="rtl" style="text-align: right;"><u>هذا مسطر.</u></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74">هذا ملون.</span></p>
    <p dir="rtl" style="text-align: right;"><i><b>هذا غامق ومائل.</b></i></p>
    <p dir="rtl" style="text-align: right;"><u><b>هذا غامق ومسطر.</b></u></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><b>هذا غامق وملون.</b></span></p>
    <p dir="rtl" style="text-align: right;"><u><i>هذا مائل ومسطر.</i></u></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><i>هذا مائل وملون.</i></span></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><u>هذا مسطر وملون.</u></span></p>
    <p dir="rtl" style="text-align: right;"><u><i><b>هذا غامق، مائل ومسطر.</b></i></u></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><i><b>هذا غامق، مائل وملون.</b></i></span></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><u><b>هذا غامق، مسطر وملون.</b></u></span></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><u><i>هذا مائل، مسطر وملون</i></u></span></p>
    <p dir="rtl" style="text-align: right;"><span style="color:#e51d74"><u><i><b>هذا غامق، مائل، مسطر وملون.</b></i></u></span></p>
    ```

- 2 Text (bold, italic, ... etc.) + inline math:

  - EN:  
     ![Example 2 Input English Sample](./documentation/assets/images/2.en.png "Example 2 Input English Sample")

    ```HTML
    <p dir="ltr" style="text-align: left">
      <b>This is Bold and here's an equation:</b>
      <math-field
        default-mode="inline-math"
        value="x+y=z"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field
      ><b>.</b>
    </p>
    <p dir="ltr" style="text-align: left">
      <i>This is Italic and here's an equation : </i
      ><math-field
        default-mode="inline-math"
        value="\sin\left(\frac{x}{y}\right)"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field
      ><i>.</i>
    </p>
    <p dir="ltr" style="text-align: left">
      <u>This is Underlined and here's an equation: </u>
      <math-field
        default-mode="inline-math"
        value="\sqrt[3]{x^2+y^2}"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field
      ><u>.</u>
    </p>
    <p dir="ltr" style="text-align: left">
      
This is Strikethrough and here's an equation: 

      <math-field
        default-mode="inline-math"
        value="\sqrt[3]{x^2+y^2}"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field
      >
.

    </p>
    <p dir="ltr" style="text-align: left">
      <span style="color: rgb(229, 29, 116)">This is Colored and here's an equation: </span>
      <math-field
        default-mode="inline-math"
        value="x^{\left(\frac{\sin45}{\cos45}\right)}"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field
      ><span style="color: rgb(229, 29, 116)">.</span>
    </p>
    ```

  - AR:  
     ![Example 2 Arabic Input Sample](./documentation/assets/images/2.ar.png "Example 2 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right">
    <b>هذا غامق وهذه معادلة:</b>
    <math-field
      default-mode="inline-math"
      value="س+ص=ع"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field
    ><b>.</b> <i>هذا مائل وهذه معادلة:</i>
    <math-field
      default-mode="inline-math"
      value="\ga\left(\frac{س}{ص}\right)"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field
    ><i>.</i>
    </p>
    <p dir="rtl" style="text-align: right">
    <u>هذا مسطر وهذه معادلة:</u>
    <math-field
      default-mode="inline-math"
      value="\sqrt[٣]{س^٢+ص^٢}"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field
    ><u>.</u> 
هذا خط بعرض النص وهذه معادلة: </s
    ><math-field
      default-mode="inline-math"
      value="س+ص=ع"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field
    >
.

    </p>
    <p dir="rtl" style="text-align: right">
    <span style="color: rgb(229, 29, 116)">هذا ملون وهذه معادلة:</span>
    <math-field
      default-mode="inline-math"
      value="س^{\left(\frac{\ga٤٥}{\gata٤٥}\right)}"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field
    ><span style="color: rgb(229, 29, 116)">.</span>
    </p>
    ```

- 3 Text + inline math + Displayed math:

  - EN:  
    ![Example 3 Input English Sample](./documentation/assets/images/3.en.png "Example 3 Input English Sample")

    ```HTML
    <p>Here's an inline equation: <math-field default-mode="inline-math" value="x^2\\;=\\;\\sqrt[3]{y^{\\frac{x}{2}}+z}" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <p>Here's a display equation:</p>
    <math-field default-mode="math" value="x^2e^{^{\\cos x}}=\\int_0^t\\frac{1}{\\sqrt{t^7}}\\;\\differentialD t" className="hoverable-mathlive-mathfield block"></math-field>
    ```

  - AR:  
    ![Example 3 Arabic Input Sample](./documentation/assets/images/3.ar.png "Example 3 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right;">هذه معادلة في نفس السطر: <math-field default-mode="inline-math" value="س^٢=\\;\\sqrt[٣]{ص^{\\frac{س}{٢}}+ع}" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <p dir="rtl" style="text-align: right;">هذه معادلة في سطر منفصل:</p>
    <math-field default-mode="math" value="س^٢\\exponentialHaa^{\\gataس}=\\int_٠^ز\\frac{١}{\\sqrt{ز^٧}}\\;دز" className="hoverable-mathlive-mathfield block"></math-field>
    ```

- 4 Text + inline math + chemistry:

  - EN:  
    ![Example 4 Input English Sample](./documentation/assets/images/4.en.png "Example 4 Input English Sample")

    ```HTML
    <p>This is an inline equation <math-field default-mode="inline-math" value="y^{\\frac{3}{2}}" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <p>This is a display chemistry equation:</p>
    <math-field default-mode="math" value="\\ce{H2O}+\\ce{2H2SO4}\\ce{->[\\Delta]}\\ce{\\ce{Na}}^-+\\ce{NaCL}\\ce{v}" className="hoverable-mathlive-mathfield block"></math-field>
    ```

  - AR:  
    ![Example 4 Arabic Input Sample](./documentation/assets/images/4.ar.png "Example 4 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right;">هذه معادلة في نفس السطر: <math-field default-mode="inline-math" value="ص^{\\frac{٢}{٣}}" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <p dir="rtl" style="text-align: right;">هذه معادلة كيميائية في سطر منفصل:</p>
    <math-field default-mode="math" value="\\ce{H2O}+\\ce{2H2SO4}\\ce{->[\\Delta]}\\ce{Na}^-+\\ce{NaCL}\\ce{v}" className="hoverable-mathlive-mathfield block"></math-field>
    ```

- 5 Text + inline math + chemistry + Table (cells include chemistry, math, text):

  - EN:  
    ![Example 5 Input English Sample](./documentation/assets/images/5.en.png "Example 5 Input English Sample")

    ```HTML
    <p>Table without Headers:</p>
    <div class="table-wrapper">
        <table>
            <tbody>
                <tr>
                    <td>Cell1</td>
                    <td>Cell2</td>
                    <td>Cell3</td>
                </tr>
                <tr>
                    <td>This is an inline equation: <math-field default-mode="inline-math" value="x+y=z\\sin45^{2+3}" className="hoverable-mathlive-mathfield inline"></math-field></td>
                    <td>This is an inline chemistry equation: <math-field default-mode="inline-math" value="\\ce{HCl}+\\ce{NaOH}\\ce{->[Heat][Heat]}\\ce{H2O}+\\ce{NaCl}\\ce{v}" className="hoverable-mathlive-mathfield inline"></math-field></td>
                    <td>Cell4</td>
                </tr>
                <tr>
                    <td>Cell5</td>
                    <td>Cell6</td>
                    <td>Cell7</td>
                </tr>
            </tbody>
        </table>
    </div>
    <p>Table with Headers:</p>
    <div class="table-wrapper">
        <table>
            <thead>
                <tr>
                    <th>Heading1</th>
                    <th>Heading2</th>
                    <th>Heading3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Cell1</td>
                    <td style="text-align: right;">Cell2</td>
                    <td>Cell3</td>
                </tr>
                <tr>
                    <td>Cell4</td>
                    <td style="text-align: center;">Cell5</td>
                    <td>Cell6</td>
                </tr>
            </tbody>
        </table>
    </div>
    ```

  - AR:  
    ![Example 5 Arabic Input Sample](./documentation/assets/images/5.ar.png "Example 5 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right;">جدول بلا عناوين:</p>
    <div class="table-wrapper">
        <table>
            <tbody>
                <tr>
                    <td dir="rtl" style="text-align: right;">خلية٣</td>
                    <td dir="rtl" style="text-align: right;">خلية٢</td>
                    <td dir="rtl" style="text-align: right;">خلية١</td>
                </tr>
                <tr>
                    <td dir="rtl" style="text-align: right;">هذه معادلة: <math-field default-mode="inline-math"
                            value="س+ص=ع\\ga٤٥^{٢+٣}" className="hoverable-mathlive-mathfield inline"></math-field>
                    </td>
                    <td dir="rtl" style="text-align: right;">هذه معادلة كيميائية: <math-field default-mode="inline-math"
                            value="\\ce{HCl}+\\ce{NaOH}\\ce{->[Heat][Heat]}\\ce{H2O}+\\ce{NaCl}\\ce{v}"
                            className="hoverable-mathlive-mathfield inline"></math-field>
                    </td>
                    <td dir="rtl" style="text-align: right;">خلية٤</td>
                </tr>
                <tr>
                    <td dir="rtl" style="text-align: right;">خلية٧</td>
                    <td dir="rtl" style="text-align: right;">خلية٦</td>
                    <td dir="rtl" style="text-align: right;">خلية٥</td>
                </tr>
            </tbody>
        </table>
    </div>
    <p dir="rtl" style="text-align: right;">جدول بعناوين:</p>
    <div class="table-wrapper">
        <table>
            <thead>
                <tr>
                    <th dir="rtl" style="text-align: right;">عنوان ٣</th>
                    <th dir="rtl" style="text-align: right;">عنوان ٢</th>
                    <th dir="rtl" style="text-align: right;">عنوان ١</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td dir="rtl" style="text-align: right;">خلية٣</td>
                    <td dir="rtl" style="text-align: center;">خلية٢</td>
                    <td dir="rtl" style="text-align: right;">خلية١</td>
                </tr>
                <tr>
                    <td dir="rtl" style="text-align: right;">خلية٦</td>
                    <td dir="rtl" style="text-align: left;">خلية٥</td>
                    <td dir="rtl" style="text-align: right;">خلية٤</td>
                </tr>
            </tbody>
        </table>
    </div>
    ```

- 6 Text + inline math + image with style:

  - EN:  
    ![Example 6 Input English Sample](./documentation/assets/images/6.en.png "Example 6 Input English Sample")

    ```HTML
    <p>Here's an equation: <math-field default-mode="inline-math" value="\\frac{x+y}{x+z}=y+2" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <div><img src="https://media.glassdoor.com/l/8b/74/4e/81/the-premises-at-night.jpg" alt="Nagwa's premises" /></div>
    <p>Here's an unordered list:</p>
    <ul>
        <li>item</li>
        <li>item</li>
        <li>item</li>
    </ul>
    <p>Here's an ordered list:</p>
    <ol>
        <li>item</li>
        <li>equation: <math-field default-mode="inline-math" value="x^2+1" className="hoverable-mathlive-mathfield inline"></math-field></li>
        <li>item</li>
    </ol>
    ```

  - AR:  
    ![Example 6 Arabic Input Sample](./documentation/assets/images/6.ar.png "Example 6 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right;">هذه معادلة: <math-field default-mode="inline-math" value="\\frac{س+ص}{س+ع}=ص+٢" className="hoverable-mathlive-mathfield inline"></math-field></p>
    <p></p>
    <div><img src="https://media.glassdoor.com/l/8b/74/4e/81/the-premises-at-night.jpg" alt="Nagwa's premises" /></div>
    <p dir="rtl" style="text-align: right;">هذه قائمة غير مرقمة:</p>
    <ul>
        <li dir="rtl" style="text-align: right;">عنصر</li>
        <li dir="rtl" style="text-align: right;">عنصر</li>
        <li dir="rtl" style="text-align: right;">عنصر</li>
    </ul>
    <p dir="rtl" style="text-align: right;">هذه قائمة مرقمة:</p>
    <ol>
        <li dir="rtl" style="text-align: right;">عنصر</li>
        <li dir="rtl" style="text-align: right;">معادلة: <math-field default-mode="inline-math" value="س^٢+١" className="hoverable-mathlive-mathfield inline"></math-field></li>
        <li dir="rtl" style="text-align: right;">عنصر</li>
    </ol>
    ```

- 7 Text + inline math + audio:

  - EN:  
     ![Example 7 Input English Sample](./documentation/assets/images/7.en.png "Example 7 Input English Sample")

    ```HTML
    <p dir="ltr" style="lang: en; text-align: left">
      Here's an equation:
      <math-field
        default-mode="inline-math"
        value="\frac{x+y}{x+z}=y+2"
        dir="ltr"
        lang="en"
        style="display: inline-block"
        read-only="true"
      ></math-field>
    </p>
    <p dir="ltr" style="lang: en; text-align: left">Here's an audio element:</p>
    <div><audio src="blob:http://localhost:3000/4d8200a1-3e5d-4445-bfb2-7404437dd7af"></audio></div>
    <p dir="ltr" style="lang: en; text-align: left">Here's an unordered list:</p>
    <ul dir="rtl" style="lang: en; text-align: right">
      <li dir="ltr" style="lang: en; text-align: left">item</li>
      <li dir="ltr" style="lang: en; text-align: left">item</li>
      <li dir="ltr" style="lang: en; text-align: left">item</li>
    </ul>
    <p dir="ltr" style="lang: en; text-align: left">Here's an ordered list:</p>
    <ol dir="rtl" style="lang: en; text-align: right">
      <li dir="ltr" style="lang: en; text-align: left">item</li>
      <li dir="ltr" style="lang: en; text-align: left">
        equation:
        <math-field
          default-mode="inline-math"
          value="x^2+1"
          dir="ltr"
          lang="en"
          style="display: inline-block"
          read-only="true"
        ></math-field>
      </li>
      <li dir="ltr" style="lang: en; text-align: left">item</li>
    </ol>
    <p dir="ltr" style="lang: en; text-align: left"></p>
    ```

  - AR:  
     ![Example 7 Arabic Input Sample](./documentation/assets/images/7.ar.png "Example 7 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right">
    هذه معادلة:
    <math-field
      default-mode="inline-math"
      value="\frac{س+ص}{س+ع}=ص+٢"
      lang="en"
      style="display: inline-block"
      read-only="true"
    ></math-field>
    </p>
    <div><audio src="blob:http://localhost:3000/656114c3-c255-4ff6-891c-43a3a9527bda"></audio></div>
    <p dir="rtl" style="text-align: right">هذه قائمة غير مرقمة:</p>
    <ul dir="rtl" style="text-align: right">
    <li dir="rtl" style="text-align: right">عنصر</li>
    <li dir="rtl" style="text-align: right">عنصر</li>
    <li dir="rtl" style="text-align: right">عنصر</li>
    </ul>
    <p dir="rtl" style="text-align: right">هذه قائمة مرقمة:</p>
    <ol dir="rtl" style="text-align: right">
    <li dir="rtl" style="text-align: right">عنصر</li>
    <li dir="rtl" style="text-align: right">
      معادلة:
      <math-field
        default-mode="inline-math"
        value="س^٢+١"
        dir="rtl"
        lang="ar"
        style="display: inline-block"
        read-only="true"
      ></math-field>
    </li>
    <li dir="rtl" style="text-align: right">عنصر</li>
    </ol>
    ```

- 8 Text + attachment:

  - EN:  
     ![Example 8 Input English Sample](./documentation/assets/images/8.en.png "Example 8 Input English Sample")

    ```HTML
    <p dir="ltr" style="text-align: left">abc</p>
    <attachments><attachment file-name="MathLive Presentation (1).pptx" url="domain.com/path/to/file"></attachment></attachments>
    ```

  - AR:  
     ![Example 8 Arabic Input Sample](./documentation/assets/images/8.ar.png "Example 8 Input Arabic Sample")

    ```HTML
    <p dir="rtl" style="text-align: right">ابجد</p>
    <attachments><attachment file-name="MathLive Presentation (1).pptx" url="domain.com/path/to/file"></attachment></attachments>
    ```

- 9 Poem:

  - حر:  
     ![Example 9 Input English Sample](./documentation/assets/images/9.1.png "Example 9 Input English Sample")

  - مشطور:  
     ![Example 9 Input English Sample](./documentation/assets/images/9.2.png "Example 9 Input English Sample")

  - عمودي:  
     ![Example 9 Input English Sample](./documentation/assets/images/9.3.png "Example 9 Input English Sample")

  - مثلث:  
     ![Example 9 Input English Sample](./documentation/assets/images/9.4.png "Example 9 Input English Sample")

    All poems are serialized to same structure with 1 minor difference, the `poemMode`. The 4 values of the poem mode in order are `free`, `vertical`, `vertical-split`, and `triangle`.

    ```HTML
    <article class="poem" data-poem-mode="free" dir="rtl" style="text-align: center;"><p>عَلى قَدْرِ أهْلِ العَزْم تأتي العَزائِمُ</p><p>وَتأتي علَى قَدْرِ الكِرامِ المَكارمُ</p><p>وَتَعْظُمُ في عَينِ الصّغيرِ صغارُها</p><p> وَتَصْغُرُ في عَين العَظيمِ العَظائِمُ</p><p>يُكَلّفُ سيفُ الدّوْلَةِ الجيشَ هَمّهُ</p><p> وَقد عَجِزَتْ عنهُ الجيوشُ الخضارمُ</p></article>
    ```

### 1.4. Example Using The API

#### 1.4.1. Using the Static API

Here's an example of how to consume the API.  
Folder Structure:

```tree
build
├─ index.html
└─ static
   ├─ css
   │  ├─ NagwaHTMLEditor-min.css
   │  └─ NagwaHTMLEditor-min.css.map
   ├─ fonts
   │  ├─ KaTeX_AMS-Regular.woff2
   │  ├─ KaTeX_Caligraphic-Bold.woff2
   │  ├─ KaTeX_Caligraphic-Regular.woff2
   │  ├─ KaTeX_Fraktur-Bold.woff2
   │  ├─ KaTeX_Fraktur-Regular.woff2
   │  ├─ KaTeX_Main-Bold.woff2
   │  ├─ KaTeX_Main-BoldItalic.woff2
   │  ├─ KaTeX_Main-Italic.woff2
   │  ├─ KaTeX_Main-Regular.woff2
   │  ├─ KaTeX_Math-BoldItalic.woff2
   │  ├─ KaTeX_Math-Italic.woff2
   │  ├─ KaTeX_SansSerif-Bold.woff2
   │  ├─ KaTeX_SansSerif-Italic.woff2
   │  ├─ KaTeX_SansSerif-Regular.woff2
   │  ├─ KaTeX_Script-Regular.woff2
   │  ├─ KaTeX_Size1-Regular.woff2
   │  ├─ KaTeX_Size2-Regular.woff2
   │  ├─ KaTeX_Size3-Regular.woff2
   │  ├─ KaTeX_Size4-Regular.woff2
   │  ├─ KaTeX_Typewriter-Regular.woff2
   │  ├─ NagwaArabicMath.woff2
   │  ├─ NagwaMath.woff2
   │  ├─ NotoNaskhArabic-Bold.woff2
   │  ├─ NotoNaskhArabic-Regular.woff2
   │  ├─ STIX2Text-Bold.woff2
   │  ├─ STIX2Text-BoldItalic.woff2
   │  ├─ STIX2Text-Italic.woff2
   │  ├─ STIX2Text-Regular.woff2
   │  ├─ droidnaskh-bold.woff2
   │  ├─ droidnaskh-regular.woff2
   │  ├─ fa-brands-400.woff2
   │  ├─ fa-light-300.woff2
   │  ├─ fa-regular-400.woff2
   │  ├─ fa-solid-900.woff2
   │  ├─ notosans-bold-webfont.woff2
   │  ├─ notosans-regular-webfont.woff2
   │  ├─ summernote.eot
   │  ├─ summernote.ttf
   │  ├─ summernote.woff
   │  ├─ summernote.woff2
   │  └─ times-extrabold.woff2
   ├─ images
   │  ├─ image-file.svg
   │  ├─ latex-icon-blue.svg
   │  ├─ latex-icon.svg
   │  ├─ pattern.svg
   │  ├─ select-arrow.svg
   │  ├─ sorting-asc.svg
   │  ├─ sorting-desc.svg
   │  ├─ sorting.svg
   │  ├─ three-dots.svg
   │  ├─ upload-cloud-icon.svg
   │  ├─ video-play-blue.svg
   │  └─ video_play.svg
   └─ js
      ├─ NagwaHTMLEditor.js
      ├─ NagwaHTMLEditor.js.LICENSE.txt
      └─ NagwaHTMLEditor.js.map

```

index.html:

```HTML
<!doctype html>
<html lang="en">

<head>
    ...
    <link href="/static/css/NagwaHTMLEditor-min.css" rel="stylesheet">
</head>

<body>
    ...
    <div id="StemEditor"></div>
    ...
    <script src="/static/js/NagwaHTMLEditor.js"></script>
    <script>
      const stemEditor = NagwaHTMLEditor.init({
        containerId: "StemEditor",
        oldValue: "<p>Hello World!</p>",
        locale: "en/eg"
      })
      const stemEditorValue = stemEditor.getValue()
    </script>
</body>

</html>
```

#### 1.4.2. Using the Component Library API

Here's an example of how to consume the Component Library API.  
After installing the library (see: [Install Component Library Using NPM](#112-using-npm)), in your react app import the editor and the needed functions from the library as follows:

```Typescript
import { FC, useEffect } from "react"
import NagwaHTMLEditor, { getEditorAPI } from "nagwa-html-editor"

const uniqueKey = "******" //make sure it's unique for every editor instance

const Component:FC = () => {

  useEffect(() => {
    const editorAPI = getEditorAPI(uniqueKey)
    console.log(editorAPI)
  })

  return <NagwaHTMLEditor uniqueKey={uniqueKey} />
}

```

## 2. Forking Guide

These instructions will get you a copy of the project up and running on your local machine.

### 2.1. Prerequisites

You have to have Node.js v14.18.1, and npm v6.14.15 installed.  
Also, check `./package.json` for all the packages used in this project

### 2.2. Installing

Clone this repo, open the terminal and navigate to the repo directory on your local machine, and then run:

```cli
npm install
```

wait until it's done and you're good to go!

**Note:** if installation fails because if npm, make sure you're using v16. if it still fails, install using v14, then re-install using v16.

**Note:** There will be a high severity audit problem when you install the packages.  
This Problem is caused by `react-scripts` package.  
This is a false positive according to [#9469 (comment)](https://github.com/facebook/create-react-app/issues/9469#issuecomment-672984368) from the maintainers on this issue, so there's nothing to worry about.

## 3. Built With

- [TypeScript](https://www.typescriptlang.org/) - The main language used.
- [Node.js **v16**](https://nodejs.org/docs/latest-v16.x/api/) - The run-time environment used to run and build the app **(Currently working using v16)**.
- [React](https://reactjs.org/) - The web framework used.
- [Slate](https://docs.slatejs.org/) - The library used to create the text editor.

## 4. Main Features

- Inserting any type of text.
- Making text bold.
- Making text italic.
- Making text underlined.
- Making text code.
- Making text superscript.
- Making text subscript.
- Inserting bulleted list.
- Inserting numbered list.
- Aligning text to any direction.
- Justify text.
- Setting the direction of the text to "ltr" or "rtl.
- Inserting a table.
- Inserting inline editable math equation.
- Inserting display editable math equation.

## 5. Git Style

### 5.1. Message Structure

A commit messages consists of three distinct parts separated by a blank line: the title, an optional body and an optional footer. The layout looks like this:

```Git
type: subject

body
```

#### 5.1.1. The Type

The type is contained within the title and can be one of these types:

- **feat:** a new feature
- **fix:** a bug fix
- **docs:** changes to documentation
- **style:** formatting, missing semi colons, etc; no code change
- **refactor:** refactoring production code
- **test:** adding tests, refactoring test; no production code change
- **chore:** updating build tasks, package manager configs, etc; no production code change

#### 5.1.2. The Subject

Subjects should be no greater than 50 characters, should begin with a capital letter and do not end with a period.

Use an imperative tone to describe what a commit does, rather than what it did. For example, use change; not changed or changes.

#### 5.1.3. The Body

Not all commits are complex enough to warrant a body, therefore it is optional and only used when a commit requires a bit of explanation and context. Use the body to explain the what and why of a commit, not the how.

When writing a body, the blank line between the title and the body is required and you should limit the length of each line to no more than 72 characters.

For more information about the style guide for Git and programming Languages check: [Udacity's Code Style Guide](https://udacity.github.io/git-styleguide/)

## React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

### Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default {
  // other rules...
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
    project: ["./tsconfig.json", "./tsconfig.node.json"],
    tsconfigRootDir: __dirname,
  },
}
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list