Skip to content

Repository files navigation

AsciiDoc WYSIWYG Editor

React TypeScript Vite Zustand Asciidoctor CodeMirror Tiptap Vitest

A modern, web-based AsciiDoc editor designed to deliver a smooth writing experience with powerful real-time preview capabilities. Built with React 19 and Vite, it integrates the Asciidoctor.js core and supports bidirectional synchronized scrolling, diagram rendering, math formulas, and local file system access.

✨ Key Features

  • Real-time Preview & Rendering:

    • Standard AsciiDoc syntax parsing powered by Asciidoctor.js.
    • Bidirectional Synchronized Scrolling: Precise line-level synchronization between the source view and the preview (based on AST line number mapping).
    • Advanced Diagram Support: Built-in Mermaid rendering engine for flowcharts, sequence diagrams, and more.
    • Math Formula Support: Integrated KaTeX for rendering LaTeX math formulas (STEM blocks).
    • Syntax Highlighting: Code block beautification using highlight.js.
  • Modern Editing Experience:

    • Dual-Mode Editing:
      • Source Mode: A high-performance code editor based on CodeMirror 6 with AsciiDoc syntax highlighting and autocompletion.
      • WYSIWYG Mode: Integrated Tiptap editor providing rich-text editing capabilities.
    • Multiple View Layouts: Switch between editor-only, preview-only, or side-by-side split-screen modes.
  • File System & Management:

    • Local File System Access: Uses the File System Access API to directly read and save .adoc files on the local disk — no upload/download required.
    • Virtual File Management: Built-in state management powered by Zustand, supporting multi-file tabs, folder structures, file renaming, and moving.
    • Browser Storage Persistence: Automatic workspace state saving via IndexedDB/LocalStorage.
  • Additional Features:

    • Dark Mode support.
    • Image Manager.
    • Export options (HTML, PDF, ZIP).

🛠 Tech Stack

📂 Project Structure

Asciidoc WYSIWYG Editor
├── App.tsx                                   # [Core] Main app entry — global layout, Toast notifications, keyboard shortcuts, and Provider wrapper
├── components                                # [UI Components] View and interaction components
│   ├── AttributesPanel.tsx                   # AsciiDoc document attributes panel (e.g., :toc:, :sectnums:)
│   ├── Autocomplete.tsx                      # Editor autocompletion component (IntelliSense)
│   ├── BlockMenu.tsx                         # Block-level element action menu (floating/context menu)
│   ├── BlockWrapper.tsx                      # React wrapper for Tiptap nodes, for custom rendering
│   ├── ContextMenu.tsx                       # Right-click context menu implementation
│   ├── ErrorBoundary.tsx                     # React error boundary — prevents editor crashes from causing blank screens
│   ├── ImageManager.tsx                      # Image resource manager — handles upload, insertion, and IndexedDB storage
│   ├── MobileHeader.tsx                      # Mobile-adapted top navigation bar
│   ├── OutlineNavigator.tsx                  # Document outline navigation (TOC)
│   ├── SearchReplaceDialog.tsx               # Search and replace dialog
│   ├── Sidebar.tsx                           # Left-side file explorer / sidebar
│   ├── SourceEditor.tsx                      # [Core] Source mode editor (based on CodeMirror 6)
│   ├── TableEditor.tsx                       # Visual table editing tool
│   ├── TiptapEditor.tsx                      # [Core] WYSIWYG editor (based on Tiptap), integrated with real-time preview logic
│   ├── Toolbar.tsx                           # Top rich-text toolbar
│   └── ui                                    # Common base UI component library
│       └── Button.tsx
├── extensions                                # [Tiptap Extensions] Custom ProseMirror nodes for AsciiDoc syntax support
│   ├── BlockNodeView.tsx                     # Generic block-level node view
│   ├── LintingExtension.ts                   # Linting extension (interfaces with the Linter)
│   ├── RawBlock.ts                           # Raw block node (stores unparseable AsciiDoc fragments)
│   ├── TableCaption.ts                       # Table caption extension
│   ├── UniqueId.ts                           # Unique ID generation extension (for synchronized scroll positioning)
│   ├── admonition-node.tsx                   # Admonition block (NOTE, TIP, WARNING, etc.) React rendering node
│   ├── include-node.tsx                      # Visual node for the Include directive
│   └── slash-commands.tsx                    # Slash commands (Notion-style "/" menu)
├── hooks                                     # [React Hooks] Custom logic reuse
│   ├── useAsyncRender.ts                     # Async rendering hook — optimizes performance for large documents
│   └── useTransientUpdates.ts                # Performance optimization hook for high-frequency updates (e.g., scroll sync)
├── index.css                                 # Global styles, Tailwind CSS entry point
├── index.html                                # HTML template
├── index.tsx                                 # Application mount point
├── lib                                       # [Core Logic Library] Business logic and utility functions
│   ├── LanguageClient.ts                     # Language Server Client (LSP) simulation layer
│   ├── asciidoc.ts                           # AsciiDoc base processing logic
│   ├── asciidoctor-renderer.ts               # [Core] Asciidoctor.js rendering engine wrapper (with Mermaid/KaTeX support)
│   ├── ast-error-collector.ts                # AST error collector (for Lint)
│   ├── ast-visitor.ts                        # AST visitor pattern implementation
│   ├── codemirror-editor.ts                  # CodeMirror editor configuration and extensions
│   ├── file-system-access.ts                 # File System Access API wrapper (local file read/write)
│   ├── html-sanitizer.ts                     # HTML sanitizer (DOMPurify) — prevents XSS
│   ├── image-service.ts                      # Image processing service
│   ├── include-preprocessor.ts               # Include directive preprocessor (resolves file references)
│   ├── indexed-db-storage.ts                 # [Storage] IndexedDB wrapper (using idb-keyval) — large file persistence
│   ├── intellisense.ts                       # IntelliSense and autocompletion logic
│   ├── kroki-renderer.ts                     # Kroki diagram service integration (supports multiple diagram DSLs)
│   ├── lazy-loader.ts                        # Resource lazy-loading utility
│   ├── log-collector.ts                      # Log collection
│   ├── markdown-converter.ts                 # Markdown to AsciiDoc converter
│   ├── paste-converter.ts                    # Paste handler (smart detection and conversion of HTML/Markdown)
│   ├── pdf-export.ts                         # PDF export (client-side generation)
│   ├── strict-schema.ts                      # Data validation schema definitions
│   ├── sync-utils.ts                         # [Core] Bidirectional scroll synchronization algorithm (Editor <-> Preview)
│   ├── theme-system.ts                       # Theme switching logic (Dark/Light Mode)
│   ├── transformer                           # [Transform Engine]
│   │   └── prosemirror-to-asciidoc.ts        # [Key] Serializes Tiptap JSON state to AsciiDoc source (with SourceMap)
│   ├── validator                             # Data validators
│   │   └── save-validator.ts                 # Pre-save data integrity validation
│   ├── worker-manager.ts                     # Web Worker manager (handles communication with Workers)
│   ├── xref-manager.ts                       # Cross-reference (xref) manager
│   └── zip-export.ts                         # Project export as ZIP archive
├── metadata.json                             # Project metadata
├── package.json                              # Dependency management (React 19, Vite, Tiptap, Asciidoctor)
├── store                                     # [State Management]
│   └── useEditorStore.ts                     # [Core] Zustand Store — manages file tree, editor state, and persistence
├── tests                                     # Unit tests
│   ├── ast-visitor.test.ts                   # AST visitor tests
│   └── setup.ts                              # Vitest test environment configuration
├── tsconfig.json                             # TypeScript compiler configuration
├── types                                     # Type definitions
│   └── lsp.ts                                # LSP protocol-related types (Diagnostic, Position, etc.)
├── types.ts                                  # Global shared type definitions (FileItem, ViewMode, etc.)
├── vite.config.ts                            # Vite build configuration (includes path aliases and plugin configs)
├── vitest.config.ts                          # Vitest test configuration
└── workers                                   # [Web Workers] Background thread scripts
    └── asciidoctor.worker.ts                 # [Performance] Runs Asciidoctor compilation and lint checks in a separate thread

🚀 Getting Started

Prerequisites

  • Node.js (v18+ recommended)
  • npm or yarn/pnpm

Install Dependencies

npm install

Run in Development Mode

Start the local development server:

npm run dev

Visit http://localhost:3000 to view the editor.

Build for Production

npm run build

Run Tests

npm test          # Run tests
npm run test:cov  # View coverage

📜 Available Scripts

Scripts defined in package.json:

  • dev: Start the Vite development server.
  • build: Run the Vite production build.
  • preview: Preview the production build locally.
  • test: Run unit tests with Vitest.
  • test:watch: Run tests in watch mode.
  • deploy: Deploy build artifacts to GitHub Pages.

🧩 Core Modules In-Depth

Renderer (lib/asciidoctor-renderer.ts)

This module wraps the Asciidoctor instance and is responsible for converting AsciiDoc text into HTML. It customizes the processing pipeline to support:

  1. Mermaid: Intercepts code blocks, generates placeholders, and renders diagrams asynchronously on the client side.
  2. KaTeX: Parses stem blocks and inline formulas.
  3. Source Map: Generates data-line attributes to establish mappings between source line numbers and DOM nodes, enabling synchronized scrolling.

File System (lib/file-system-access.ts)

Wraps the browser's native FileSystemFileHandle interface.

  • showOpenFilePicker: Opens the file picker dialog.
  • showSaveFilePicker: Save As functionality.
  • Provides a fallback mechanism for browsers that do not support the native API, using traditional <input type="file"> and Blob downloads.

State Management (store/useEditorStore.ts)

Manages the global editor state, including:

  • File tree structure (Files, Folders).
  • Currently active file and view mode.
  • UI state (sidebar visibility, dialog visibility).
  • Synchronized scroll position information (highlightLine, syncToLine).

About

Asciidoc WYSIWYG Editor — A Web-based Visual Editor for AsciiDoc

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages