]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Added base table support and started resize handling
authorDan Brown <redacted>
Fri, 21 Jun 2024 12:47:47 +0000 (13:47 +0100)
committerDan Brown <redacted>
Fri, 21 Jun 2024 12:47:47 +0000 (13:47 +0100)
package-lock.json
package.json
resources/js/wysiwyg/index.ts
resources/js/wysiwyg/nodes/index.ts
resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts [new file with mode: 0644]
resources/sass/_editor.scss
resources/views/pages/parts/wysiwyg-editor.blade.php

index 0757e786873c06a69a5625191fc0aace5e2d06fd..646750df49a2a974c8f974fe7103c41376d20dbb 100644 (file)
@@ -24,6 +24,7 @@
         "@lexical/list": "^0.15.0",
         "@lexical/rich-text": "^0.15.0",
         "@lexical/selection": "^0.15.0",
+        "@lexical/table": "^0.15.0",
         "@lexical/utils": "^0.15.0",
         "@lezer/highlight": "^1.2.0",
         "@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
index 732bb1759806f3c31ca2d1382002271eea6cc5d4..d649b54e2d21595c0d5a5e3269a463cba58d8995 100644 (file)
@@ -48,6 +48,7 @@
     "@lexical/list": "^0.15.0",
     "@lexical/rich-text": "^0.15.0",
     "@lexical/selection": "^0.15.0",
+    "@lexical/table": "^0.15.0",
     "@lexical/utils": "^0.15.0",
     "@lezer/highlight": "^1.2.0",
     "@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
index 41207b706f4237e7d4fa907633e492c2b5574f52..b910b2eb6196ccd3a6c4abd3ce9dcd0c5c5e183e 100644 (file)
@@ -5,6 +5,7 @@ import {mergeRegister} from '@lexical/utils';
 import {getNodesForPageEditor} from './nodes';
 import {buildEditorUI} from "./ui";
 import {setEditorContentFromHtml} from "./actions";
+import {registerTableResizer} from "./ui/framework/helpers/table-resizer";
 
 export function createPageEditorInstance(editArea: HTMLElement) {
     const config: CreateEditorArgs = {
@@ -21,6 +22,7 @@ export function createPageEditorInstance(editArea: HTMLElement) {
     mergeRegister(
         registerRichText(editor),
         registerHistory(editor, createEmptyHistoryState(), 300),
+        registerTableResizer(editor, editArea),
     );
 
     setEditorContentFromHtml(editor, startingHtml);
index 03fcd33a5b3e6606ae36aac7be90b5e4a7994679..ea6206ac2bad545e72f9d9ecbd7c884a9fc6cc5d 100644 (file)
@@ -6,6 +6,7 @@ import {LinkNode} from "@lexical/link";
 import {ImageNode} from "./image";
 import {DetailsNode, SummaryNode} from "./details";
 import {ListItemNode, ListNode} from "@lexical/list";
+import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
 
 /**
  * Load the nodes for lexical.
@@ -17,6 +18,9 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         QuoteNode, // Todo - Create custom
         ListNode, // Todo - Create custom
         ListItemNode,
+        TableNode, // Todo - Create custom,
+        TableRowNode,
+        TableCellNode,
         ImageNode,
         DetailsNode, SummaryNode,
         CustomParagraphNode,
diff --git a/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts b/resources/js/wysiwyg/ui/framework/helpers/table-resizer.ts
new file mode 100644 (file)
index 0000000..53017e9
--- /dev/null
@@ -0,0 +1,68 @@
+import {LexicalEditor} from "lexical";
+import {el} from "../../../helpers";
+
+type MarkerDomRecord = {x: HTMLElement, y: HTMLElement};
+
+class TableResizer {
+    protected editor: LexicalEditor;
+    protected editArea: HTMLElement;
+    protected markerDom: MarkerDomRecord|null = null;
+
+    constructor(editor: LexicalEditor, editArea: HTMLElement) {
+        this.editor = editor;
+        this.editArea = editArea;
+        this.setupListeners();
+    }
+
+    setupListeners() {
+        this.editArea.addEventListener('mousemove', event => {
+            const cell = (event.target as HTMLElement).closest('td,th');
+            if (cell) {
+                this.onCellMouseMove(cell as HTMLElement, event);
+            }
+        });
+    }
+
+    onCellMouseMove(cell: HTMLElement, event: MouseEvent) {
+        const rect = cell.getBoundingClientRect();
+        const midX = rect.left + (rect.width / 2);
+        const midY = rect.top + (rect.height / 2);
+        const xMarkerPos = event.clientX <= midX ? rect.left : rect.right;
+        const yMarkerPos = event.clientY <= midY ? rect.top : rect.bottom;
+        this.updateMarkersTo(cell, xMarkerPos, yMarkerPos);
+    }
+
+    updateMarkersTo(cell: HTMLElement, xPos: number, yPos: number) {
+        const markers: MarkerDomRecord = this.getMarkers();
+        const table = cell.closest('table') as HTMLElement;
+        const tableRect = table.getBoundingClientRect();
+
+        markers.x.style.left = xPos + 'px';
+        markers.x.style.height = tableRect.height + 'px';
+        markers.x.style.top = tableRect.top + 'px';
+
+        markers.y.style.top = yPos + 'px';
+        markers.y.style.left = tableRect.left + 'px';
+        markers.y.style.width = tableRect.width + 'px';
+    }
+
+    getMarkers(): MarkerDomRecord {
+        if (!this.markerDom) {
+            this.markerDom = {
+                x: el('div', {class: 'editor-table-marker-column'}),
+                y: el('div', {class: 'editor-table-marker-row'}),
+            }
+            this.editArea.after(this.markerDom.x, this.markerDom.y);
+        }
+
+        return this.markerDom;
+    }
+}
+
+
+export function registerTableResizer(editor: LexicalEditor, editorArea: HTMLElement): (() => void) {
+    const resizer = new TableResizer(editor, editorArea);
+
+    // TODO - Strip/close down resizer
+    return () => {};
+}
\ No newline at end of file
index f8c895afd351ec4dd4962c29c56361a500c1e7c3..ad1f5a339ea61a3b86ab6efc5ad1f661ce3e31b6 100644 (file)
     cursor: sw-resize;
   }
 }
+
+.editor-table-marker-row,
+.editor-table-marker-column {
+  position: fixed;
+  background-color: var(--editor-color-primary);
+  z-index: 99;
+  user-select: none;
+  opacity: 0;
+  &:hover {
+    opacity: 0.4;
+  }
+}
+.editor-table-marker-column {
+  width: 4px;
+  cursor: col-resize;
+}
+.editor-table-marker-row {
+  height: 4px;
+  cursor: row-resize;
+}
\ No newline at end of file
index 6414027697c33ae3479a555662de9288f843916f..5cd60bbc69b549c8ee9b28c6509b2ac88a93ebbe 100644 (file)
             <p class="callout info">
                 Hello there, this is an info callout
             </p>
+
+            <h3>Table</h3>
+
+            <table>
+                <thead>
+                <tr>
+                    <th>Cell A</th>
+                    <th>Cell B</th>
+                    <th>Cell C</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr>
+                    <td>Cell D</td>
+                    <td>Cell E</td>
+                    <td>Cell F</td>
+                </tr>
+                </tbody>
+            </table>
         </div>
     </div>