OverType

repository·main·Indexed 25 days ago

https://github.com/panphora/overtype

A lightweight (~117KB), framework-agnostic markdown editor library (v2.4.0) that uses an invisible textarea overlay to achieve perfect WYSIWYG alignment. It features a built-in toolbar, multiple view modes (Normal, Plain Text, and Preview), a standalone MarkdownParser for SSR, and a native Web Component. To maintain 1:1 character mapping, it requires monospace fonts and does not render images.

Tokens
19.8K
Snippets
43
Records
108
Agent score
85%

What's inside overtype

  1. Understand OverType's architectural limitations

    main

    OverType is a lightweight (~60KB minified) editor component designed for perfect character alignment using a line-by-line DOM structure. Because of this architecture, the following features are not supported and are intentionally excluded:

    • Images: Images break the character grid alignment required for the overlay model.
    • Tables: Variable column widths and cell navigation (Tab) conflict with the monospace grid and textarea behavior.
    • Nested Lists: Varying indentation widths break character grid alignment and cause visual 'jumping' during parsing.
    • Split Pane Preview: OverType is designed to be the preview itself; it does not support a side-by-side view.
    • File Management: OverType is an editor component, not an IDE. File trees and project management must be handled by the host application.
    • Modal Keybindings: Vim or Emacs keybindings are not supported as they break native textarea behavior.
  2. Understand the OverType Two-Layer Architecture

    main

    OverType uses a Transparent Overlay Technique to achieve WYSIWYG markdown editing. It consists of two perfectly aligned layers:

    1. Input Layer (textarea.overtype-input): A completely transparent textarea that handles all user input, cursor management, and selection.
    2. Preview Layer (div.overtype-preview): A styled markdown rendering div positioned exactly beneath the textarea.

    To maintain pixel-perfect alignment, both layers must share identical:

    • Font properties: family, size, weight, variant, synthesis, kerning, and ligatures.
    • Box model: padding, margin, border, and box-sizing.
    • Text layout: white-space, word-wrap, word-break, tab-size, line-height, and letter-spacing.
    • Positioning: absolute positioning, matching width/height, and identical overflow/scrolling behavior.
  3. Configure OverType View Modes

    main

    OverType supports three distinct visual modes, which can be switched via CSS class-based toggling:

    • Normal Mode: Standard overlay editing. The textarea is transparent, the preview shows styled markdown, and syntax markers are visible.
    • Plain Mode: Raw markdown editing. The preview is hidden, the textarea is fully visible, and a system font is used for true plain text.
    • Preview Mode: Read-only rendering. The textarea is hidden, the preview is interactive (e.g., clickable links), and syntax markers are hidden via CSS.
  4. Use OverType via CDN (Global Script Tag)

    main

    For a simple global script approach, include the minified IIFE build via a script tag.

    <script src="https://cdn.jsdelivr.net/npm/overtype@latest/dist/overtype.min.js"></script>
    <script>
      const [editor] = new OverType('#editor', { value: '# Hello' });
    </script>
  5. Implement Autocompletion and Suggestion Popups

    main

    OverType does not include autocompletion in its core. Instead, it is designed to be implemented within the host application. OverType provides the necessary hooks to build features like GitHub-style @mention or #issue popups by exposing the editor.textarea, onChange, getValue, and setValue methods.

    To implement autocompletion, you should:

    1. Use the host application to detect trigger patterns (e.g., @ or #).
    2. Use the existing Floating UI positioning pattern (similar to how LinkTooltip works) to display suggestions.
    3. Ensure the popup hides on the same signals as LinkTooltip (cursor moving out of trigger context, scroll, or blur).
    4. Handle keyboard navigation (↑↓/Enter/Esc) without breaking the native textarea behavior.
  6. Integrate <overtype-editor> with React, Vue, or Angular

    main

    Since <overtype-editor> is a native Web Component, it can be integrated into modern frameworks by handling its custom events and attributes.

    // React Example
    function App() {
      const [content, setContent] = useState('# Hello React!');
      return (
        <overtype-editor
          value={content}
          onchange={(e) => setContent(e.detail.value)}
          theme="solar"
          toolbar
        />
      );
    }
    <!-- Vue Example -->
    <template>
      <overtype-editor
        :value="content"
        @change="handleChange"
        theme="cave"
        toolbar
      />
    </template>
    
    <script>
    export default {
      data() {
        return { content: '# Hello Vue!' };
      },
      methods: {
        handleChange(e) {
          this.content = e.detail.value;
        }
      }
    };
    </script>
    // Angular Example
    @Component({
      template: `
        <overtype-editor
          [value="content"
          (change)="handleChange($event)"
          theme="solar"
          toolbar>
        </overtype-editor>
      `
    })
    export class AppComponent {
      content = '# Hello Angular!';
      handleChange(event: CustomEvent) {
        this.content = event.detail.value;
      }
    }
  7. Migrate from OverType v1.x to v2.0

    main

    The Toolbar API has changed. The old options customToolbarButtons, hideButtons, and buttonOrder have been removed.

    In v2.0, use the toolbarButtons option with an explicit array of buttons. You can import built-in buttons from the overtype package.

    import { toolbarButtons } from 'overtype';
    
    {
      toolbar: true,
      toolbarButtons: [
        toolbarButtons.bold,
        toolbarButtons.italic,
        { name: 'custom', icon: '...', action: ({ editor, getValue }) => {} }
      ]
    }
  8. Configure multiple editors via Data Attributes

    main

    You can configure multiple OverType editors using HTML data-ot-* attributes and the OverType.initFromData() method. Kebab-case attributes are automatically converted to camelCase options (e.g., data-ot-show-stats becomes showStats).

    Supported attributes:

    • toolbar
    • theme
    • value
    • placeholder
    • autofocus
    • auto-resize
    • min-height
    • max-height
    • font-size
    • line-height
    • show-stats
    • smart-lists
    • show-active-line-raw
    • textarea-props / textarea-*

    Note: Complex options like toolbarButtons, onChange, onKeydown, onFocus, onBlur, statsFormatter, codeHighlighter, colors, and mobile cannot be set via data attributes and must be configured using JavaScript.

    <div class="editor" data-ot-toolbar="true" data-ot-theme="cave"></div>
    <div class="editor" data-ot-auto-resize="true" data-ot-min-height="200px"></div>
    <div class="editor" data-ot-show-stats="true" data-ot-placeholder="Write here..."></div>
    
    <script>
      OverType.initFromData('.editor', { fontSize: '14px' }); // defaults
    </script>
  9. Provide multi-line content to <overtype-editor>

    main

    You can initialize the editor with multi-line content using two methods:

    1. Attribute with escaped sequences: Use the value attribute with \n for newlines. This is recommended for inline HTML.
    2. Element text content: Place the raw multi-line text between the opening and closing <overtype-editor> tags. If the value attribute is missing, the component uses the textContent as the initial value.
    <!-- Using escaped sequences in attribute -->
    <overtype-editor
      value="# Hello\n\nThis content spans multiple lines using escaped newlines."
      height="220px">
    </overtype-editor>
    
    <!-- Using element text content -->
    <overtype-editor height="220px">
    # Hello
    
    This content spans multiple lines using element text content.
    </overtype-editor>
  10. Configure native textarea attributes via HTML

    main

    To ensure the underlying <textarea> participates in native form validation (e.g., required, name, maxLength), you can pass attributes through OverType using two methods:

    1. Individual attributes: Use the pattern data-ot-textarea-<attr>.
    2. JSON object: Use data-ot-textarea-props with a JSON string containing the full object.

    Important: To make a field optional, simply omit the attribute. Do not use data-ot-textarea-required="false", as the presence of the attribute (even if set to false) will mark the field as required in HTML.

    <!-- One attribute per prop: data-ot-textarea-<attr> -->
    <div class="editor" data-ot-textarea-required data-ot-textarea-name="message"></div>
    
    <!-- Or the whole object as JSON -->
    <div class="editor" data-ot-textarea-props='{"required":true,"maxLength":500,"name":"message"}'></div>
  11. Quick Start: Initialize and control the editor

    main

    Initialize a new editor instance by passing a selector and an options object. The constructor returns an array where the first element is the editor instance. You can then use methods to get/set content and change themes.

    // Create a single editor
    const [editor] = new OverType('#editor', {
      value: '# Hello World',
      theme: 'solar'
    });
    
    // Get/set content
    editor.getValue();
    editor.setValue('# New Content');
    
    // Change theme for this instance
    editor.setTheme('cave');