]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Fixed code in lists, removed extra old alignment code 5415/head
authorDan Brown <redacted>
Sun, 16 Feb 2025 15:09:33 +0000 (15:09 +0000)
committerDan Brown <redacted>
Sun, 16 Feb 2025 15:09:33 +0000 (15:09 +0000)
Code in lists could throw error on parse due to inner <code> tag being
parsed but not actually used within a <pre>, so this updates the
importDOM to disregard childdren for code blocks.

This also improves the invariant implementation to not be so
dev/debugger based, and to include vars in the output.

resources/js/wysiwyg/lexical/core/LexicalCommands.ts
resources/js/wysiwyg/lexical/core/LexicalConstants.ts
resources/js/wysiwyg/lexical/core/LexicalNode.ts
resources/js/wysiwyg/lexical/core/index.ts
resources/js/wysiwyg/lexical/core/nodes/LexicalElementNode.ts
resources/js/wysiwyg/lexical/core/nodes/LexicalTextNode.ts
resources/js/wysiwyg/lexical/core/shared/invariant.ts
resources/js/wysiwyg/lexical/html/index.ts
resources/js/wysiwyg/lexical/rich-text/LexicalCodeBlockNode.ts
resources/js/wysiwyg/lexical/rich-text/index.ts

index 0f1c0a5d31eab1f180d076873179d6fcfad9bdfc..f995237a0cf26640b62cf356366b53d21adf17c3 100644 (file)
@@ -8,7 +8,6 @@
 
 import type {
   BaseSelection,
-  ElementFormatType,
   LexicalCommand,
   LexicalNode,
   TextFormatType,
@@ -91,8 +90,6 @@ export const OUTDENT_CONTENT_COMMAND: LexicalCommand<void> = createCommand(
 );
 export const DROP_COMMAND: LexicalCommand<DragEvent> =
   createCommand('DROP_COMMAND');
-export const FORMAT_ELEMENT_COMMAND: LexicalCommand<ElementFormatType> =
-  createCommand('FORMAT_ELEMENT_COMMAND');
 export const DRAGSTART_COMMAND: LexicalCommand<DragEvent> =
   createCommand('DRAGSTART_COMMAND');
 export const DRAGOVER_COMMAND: LexicalCommand<DragEvent> =
index 82461e74d9592ca43f5eb9f0fd26667ba54e4122..55668f1e4bcebc91766f9c3626ea5555de525dbc 100644 (file)
@@ -6,7 +6,6 @@
  *
  */
 
-import type {ElementFormatType} from './nodes/LexicalElementNode';
 import type {
   TextDetailType,
   TextFormatType,
@@ -111,27 +110,6 @@ export const DETAIL_TYPE_TO_DETAIL: Record<TextDetailType | string, number> = {
   unmergeable: IS_UNMERGEABLE,
 };
 
-export const ELEMENT_TYPE_TO_FORMAT: Record<
-  Exclude<ElementFormatType, ''>,
-  number
-> = {
-  center: IS_ALIGN_CENTER,
-  end: IS_ALIGN_END,
-  justify: IS_ALIGN_JUSTIFY,
-  left: IS_ALIGN_LEFT,
-  right: IS_ALIGN_RIGHT,
-  start: IS_ALIGN_START,
-};
-
-export const ELEMENT_FORMAT_TO_TYPE: Record<number, ElementFormatType> = {
-  [IS_ALIGN_CENTER]: 'center',
-  [IS_ALIGN_END]: 'end',
-  [IS_ALIGN_JUSTIFY]: 'justify',
-  [IS_ALIGN_LEFT]: 'left',
-  [IS_ALIGN_RIGHT]: 'right',
-  [IS_ALIGN_START]: 'start',
-};
-
 export const TEXT_MODE_TO_TYPE: Record<TextModeType, 0 | 1 | 2> = {
   normal: IS_NORMAL,
   segmented: IS_SEGMENTED,
index 163bb8c31c85119a59802db6fb5933ce4b1d8f55..7306e6bca2755a578826f4bf87f37d24935ed465 100644 (file)
@@ -146,6 +146,12 @@ type NodeName = string;
  * Output for a DOM conversion.
  * Node can be set to 'ignore' to ignore the conversion and handling of the DOMNode
  * including all its children.
+ *
+ * You can specify a function to run for each converted child (forChild) or on all
+ * the child nodes after the conversion is complete (after).
+ * The key difference here is that forChild runs for every deeply nested child node
+ * of the current node, whereas after will run only once after the
+ * transformation of the node and all its children is complete.
  */
 export type DOMConversionOutput = {
   after?: (childLexicalNodes: Array<LexicalNode>) => Array<LexicalNode>;
index 5ef926b5afc493757343a78ab380ac5354c7a56c..92cb4a1ca9becf353bf0890d5abcb6e91e78bec1 100644 (file)
@@ -49,15 +49,12 @@ export type {
 } from './LexicalNode';
 export type {
   BaseSelection,
-  ElementPointType as ElementPoint,
   NodeSelection,
   Point,
   PointType,
   RangeSelection,
-  TextPointType as TextPoint,
 } from './LexicalSelection';
 export type {
-  ElementFormatType,
   SerializedElementNode,
 } from './nodes/LexicalElementNode';
 export type {SerializedRootNode} from './nodes/LexicalRootNode';
@@ -87,7 +84,6 @@ export {
   DRAGSTART_COMMAND,
   DROP_COMMAND,
   FOCUS_COMMAND,
-  FORMAT_ELEMENT_COMMAND,
   FORMAT_TEXT_COMMAND,
   INDENT_CONTENT_COMMAND,
   INSERT_LINE_BREAK_COMMAND,
index 9624af67e7eb38b04a3443f4dd88757c567873b8..9ad5084114150ee04c1a45b946d61092f941ad2a 100644 (file)
@@ -46,15 +46,6 @@ export type SerializedElementNode<
   SerializedLexicalNode
 >;
 
-export type ElementFormatType =
-  | 'left'
-  | 'start'
-  | 'center'
-  | 'right'
-  | 'end'
-  | 'justify'
-  | '';
-
 // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
 export interface ElementNode {
   getTopLevelElement(): ElementNode | null;
index 4a3a489504e1d6a054d352566467372d778b5090..7f1b4f305154472bae7cc8a573bb10dbd3c6632e 100644 (file)
@@ -1314,6 +1314,11 @@ const nodeNameToTextFormat: Record<string, TextFormatType> = {
 
 function convertTextFormatElement(domNode: HTMLElement): DOMConversionOutput {
   const format = nodeNameToTextFormat[domNode.nodeName.toLowerCase()];
+
+  if (format === 'code' && domNode.closest('pre')) {
+    return {node: null};
+  }
+
   if (format === undefined) {
     return {node: null};
   }
index 0e73848bac1d0b9f3afc598f6078e5062fdfa329..8e008c11c5109910620be5cb39926237f76182b5 100644 (file)
@@ -18,9 +18,9 @@ export default function invariant(
     return;
   }
 
-  throw new Error(
-    'Internal Lexical error: invariant() is meant to be replaced at compile ' +
-      'time. There is no runtime version. Error: ' +
-      message,
-  );
+  for (const arg of args) {
+    message = (message || '').replace('%s', arg);
+  }
+
+  throw new Error(message);
 }
index 5c3cb6cce29feb4d7fd9c5a09eaadf576bde6f5e..5018e10b4f2c3c4ef75a4af7f8efcfd0abbd1378 100644 (file)
@@ -11,7 +11,6 @@ import type {
   DOMChildConversion,
   DOMConversion,
   DOMConversionFn,
-  ElementFormatType,
   LexicalEditor,
   LexicalNode,
 } from 'lexical';
@@ -58,6 +57,7 @@ export function $generateNodesFromDOM(
       }
     }
   }
+
   $unwrapArtificalNodes(allArtificialNodes);
 
   return lexicalNodes;
@@ -324,8 +324,6 @@ function wrapContinuousInlines(
   nodes: Array<LexicalNode>,
   createWrapperFn: () => ElementNode,
 ): Array<LexicalNode> {
-  const textAlign = (domNode as HTMLElement).style
-    .textAlign as ElementFormatType;
   const out: Array<LexicalNode> = [];
   let continuousInlines: Array<LexicalNode> = [];
   // wrap contiguous inline child nodes in para
index cbe6918488724dcf59bd5fa6b7b06d7d2c260edc..49ba7754c4c7d541a84fa68ef768785c1c5c21fb 100644 (file)
@@ -145,7 +145,14 @@ export class CodeBlockNode extends DecoratorNode<EditorDecoratorAdapter> {
                             node.setId(element.id);
                         }
 
-                        return { node };
+                        return {
+                            node,
+                            after(childNodes): LexicalNode[] {
+                                // Remove any child nodes that may get parsed since we're manually
+                                // controlling the code contents.
+                                return [];
+                            },
+                        };
                     },
                     priority: 3,
                 };
index c585c028a5ad2ce68b29195beeb3250a38b2c467..477fdd78105a6baab09fb0c1e038f6ba699606ce 100644 (file)
@@ -8,7 +8,6 @@
 
 import type {
   CommandPayloadType,
-  ElementFormatType,
   LexicalCommand,
   LexicalEditor,
   PasteCommandType,
@@ -44,7 +43,6 @@ import {
   DRAGSTART_COMMAND,
   DROP_COMMAND,
   ElementNode,
-  FORMAT_ELEMENT_COMMAND,
   FORMAT_TEXT_COMMAND,
   INSERT_LINE_BREAK_COMMAND,
   INSERT_PARAGRAPH_COMMAND,
@@ -285,25 +283,6 @@ export function registerRichText(editor: LexicalEditor): () => void {
       },
       COMMAND_PRIORITY_EDITOR,
     ),
-    editor.registerCommand<ElementFormatType>(
-      FORMAT_ELEMENT_COMMAND,
-      (format) => {
-        const selection = $getSelection();
-        if (!$isRangeSelection(selection) && !$isNodeSelection(selection)) {
-          return false;
-        }
-        const nodes = selection.getNodes();
-        for (const node of nodes) {
-          const element = $findMatchingParent(
-            node,
-            (parentNode): parentNode is ElementNode =>
-              $isElementNode(parentNode) && !parentNode.isInline(),
-          );
-        }
-        return true;
-      },
-      COMMAND_PRIORITY_EDITOR,
-    ),
     editor.registerCommand<boolean>(
       INSERT_LINE_BREAK_COMMAND,
       (selectStart) => {