Skip to content

Editor Component

Overview

The Editor component is a sophisticated rich text editing interface built on the Lexical framework. It provides advanced document editing capabilities with real-time formatting, evidence citation, requirement tracking, and AI-assisted content generation.

Features

  1. Rich Text Editing: Full-featured text editor with formatting, styles, and multimedia support
  2. Evidence Highlighting: Ability to highlight and link evidence to support document claims
  3. Requirement Tracking: Integration with tender requirements for tracking completion status
  4. Real-time Collaboration: Supports multiple users editing simultaneously
  5. Document Versioning: Tracks document history and revisions
  6. AI-Assisted Writing: Integration with AI services for content suggestions and improvements
  7. Customisable Toolbar: Context-sensitive formatting options

Implementation

The component is built using React with the Lexical editor framework and integrates with the BidScript backend for document management.

import { useEffect, useState, useRef } from "react";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
import { useWorkspaceContext } from "@/components/Editor/WorkspaceContext";
import { ToolbarPlugin } from "@/components/Editor/plugins/ToolbarPlugin";
import { HighlightPlugin } from "@/components/Editor/plugins/HighlightPlugin";
import { RestoreEditorStatePlugin } from "@/components/Editor/plugins/restoreEditorStatePlugin";
import { ExportEditorStatePlugin } from "@/components/Editor/plugins/exportEditorStatePlugin";
import { theme } from "@/components/Editor/themes/ExampleTheme";

Props

Prop Type Description
initialState string | null Initial editor content state (serialized JSON)
readOnly boolean Whether the editor is in read-only mode
onChange function Callback function when content changes
onSave function Callback function when content is saved
requirements Requirement[] Array of requirements to track in the document
highlightedEvidence Evidence[] Array of evidence citations to highlight

State Management

The component manages several state variables through a combination of internal state and context providers:

// Editor state management
const { editorState, setEditorState } = useWorkspaceContext();
const [isEditorReady, setIsEditorReady] = useState<boolean>(false);
const [activeFormatters, setActiveFormatters] = useState<FormatterState>({
  bold: false,
  italic: false,
  underline: false,
  strikethrough: false,
  code: false,
  highlight: false,
});

// Content tracking
const [wordCount, setWordCount] = useState<number>(0);
const [charCount, setCharCount] = useState<number>(0);
const [requirementCoverage, setRequirementCoverage] = useState<number>(0);

// Collaboration state
const [collaborators, setCollaborators] = useState<Collaborator[]>([]);
const [pendingChanges, setPendingChanges] = useState<Change[]>([]);

Lexical Configuration

The Lexical editor is configured with custom nodes and plugins:

const initialConfig = {
  namespace: "BidScriptEditor",
  theme,
  onError: handleEditorError,
  nodes: [
    HeadingNode,
    ListNode,
    ListItemNode,
    QuoteNode,
    CodeNode,
    CodeHighlightNode,
    TableNode,
    TableCellNode,
    TableRowNode,
    AutoLinkNode,
    LinkNode,
    HighlightNode,
  ],
};

Editor Plugins

The editor utilizes several custom plugins for enhanced functionality:

<LexicalComposer initialConfig={initialConfig}>
  <div className="editor-container">
    <ToolbarPlugin />
    <div className="editor-inner">
      <RichTextPlugin
        contentEditable={<ContentEditable className="editor-input" />}
        placeholder={<Placeholder />}
        ErrorBoundary={LexicalErrorBoundary}
      />
      <HistoryPlugin />
      <AutoFocusPlugin />
      <ListPlugin />
      <LinkPlugin />
      <TabIndentationPlugin />
      <HighlightPlugin highlightedEvidence={highlightedEvidence} />
      <RestoreEditorStatePlugin initialState={initialState} />
      <ExportEditorStatePlugin onChange={handleEditorChange} />
      <ChangeAnalysisPlugin requirements={requirements} />
    </div>
  </div>
</LexicalComposer>

Methods

// Editor state management
const handleEditorChange = (editorState) =>
// Updates editor state and processes changes

const saveEditorContent = async () =>
// Saves the current editor content to the server

// Formatting functions
const applyFormat = (format, value) =>
// Applies specified formatting to selected text

const insertLink = (url, text) =>
// Inserts a hyperlink at the current cursor position

// Evidence and requirements
const highlightEvidence = (evidenceId, text) =>
// Highlights text and links it to specific evidence

const checkRequirementCoverage = () =>
// Analyzes content for requirement coverage

Usage Example

import { Editor } from "@/components/workspace/Editor";
import { useWorkspaceContext } from "@/components/Editor/WorkspaceContext";

const DocumentEditor = () => {
  const { editorState, requirements, evidence } = useWorkspaceContext();

  return (
    <div className="document-editor">
      <h2>Document Editor</h2>
      <Editor
        initialState={editorState}
        requirements={requirements}
        highlightedEvidence={evidence}
        onChange={handleEditorChange}
        onSave={handleSaveDocument}
      />
    </div>
  );
};

Dependencies

// Core editor dependencies
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";

// BidScript custom components
import { useWorkspaceContext } from "@/components/Editor/WorkspaceContext";
import { ToolbarPlugin } from "@/components/Editor/plugins/ToolbarPlugin";
import { HighlightPlugin } from "@/components/Editor/plugins/HighlightPlugin";

Notes

  • Optimised for performance with large documents
  • Implements custom nodes for BidScript-specific features
  • Uses WebSockets for real-time collaboration
  • Supports keyboard shortcuts for common operations
  • Includes accessibility features for inclusive editing experience