{"id":30412168,"url":"https://github.com/panphora/overtype","last_synced_at":"2025-08-23T16:14:06.328Z","repository":{"id":310381431,"uuid":"1038331121","full_name":"panphora/overtype","owner":"panphora","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-17T17:34:25.000Z","size":2256,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-17T19:24:58.684Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/panphora.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-15T02:17:49.000Z","updated_at":"2025-08-17T18:49:38.000Z","dependencies_parsed_at":"2025-08-17T19:25:00.453Z","dependency_job_id":"4a1e9d93-e9b8-4b94-a866-528d84a4b8bf","html_url":"https://github.com/panphora/overtype","commit_stats":null,"previous_names":["panphora/overtype"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/panphora/overtype","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panphora%2Fovertype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panphora%2Fovertype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panphora%2Fovertype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panphora%2Fovertype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/panphora","download_url":"https://codeload.github.com/panphora/overtype/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panphora%2Fovertype/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271553235,"owners_count":24779820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-22T02:01:27.813Z","updated_at":"2025-08-23T16:14:06.319Z","avatar_url":"https://github.com/panphora.png","language":"JavaScript","readme":"# OverType\n\nA lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~82KB minified with all features.\n\n## Features\n\n- 👻 **Invisible textarea overlay** - Transparent input layer overlaid on styled preview for seamless editing\n- 🎨 **Global theming** - Solar (light) and Cave (dark) themes that apply to all instances\n- ⌨️ **Keyboard shortcuts** - Common markdown shortcuts (Cmd/Ctrl+B for bold, etc.)\n- 📱 **Mobile optimized** - Responsive design with mobile-specific styles\n- 🔄 **DOM persistence aware** - Recovers from existing DOM (perfect for HyperClay and similar platforms)\n- 🚀 **Lightweight** - ~82KB minified\n- 🎯 **Optional toolbar** - Clean, minimal toolbar with all essential formatting\n- ✨ **Smart shortcuts** - Keyboard shortcuts with selection preservation\n- 📝 **Smart list continuation** - GitHub-style automatic list continuation on Enter\n- 🔧 **Framework agnostic** - Works with React, Vue, vanilla JS, and more\n\n## How it works\n\n![OverType Architecture Diagram](https://websharebox.s3.amazonaws.com/diagram.png)\n\nWe overlap an invisible textarea on top of styled output, giving the illusion of editing styled text using a plain textarea.\n\n## Comparisons\n\n| Feature | OverType | HyperMD | Milkdown | TUI Editor | EasyMDE |\n|---------|----------|---------|----------|------------|---------|\n| **Size** | ~82KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |\n| **Dependencies** | Bundled | CodeMirror | ProseMirror + plugins | Multiple libs | CodeMirror |\n| **Setup** | Single file | Complex config | Build step required | Complex config | Moderate |\n| **Approach** | Invisible textarea | ContentEditable | ContentEditable | ContentEditable | CodeMirror |\n| **Mobile** | Perfect native | Issues common | Issues common | Issues common | Limited |\n| **Markdown syntax** | Visible | Hidden | Hidden | Toggle | Visible |\n| **Advanced features** | Basic | Full | Full | Full | Moderate |\n| **Best for** | Simple, fast, mobile | Full WYSIWYG | Modern frameworks | Enterprise apps | Classic editing |\n\n**Choose OverType when you need:**\n- Tiny bundle size (10x smaller than alternatives)\n- Zero dependencies - single file that works immediately\n- Perfect native browser features (undo/redo, mobile keyboards, spellcheck)\n- Dead-simple integration without build tools\n- Easy to understand, modify, and extend\n- Excellent mobile support with visible markdown syntax\n\n**Choose other editors when you need:**\n- Full WYSIWYG with hidden markdown syntax\n- Advanced features like tables, diagrams, or collaborative editing\n- Rich plugin ecosystems\n- Enterprise features and extensive customization\n- Framework-specific integration (React, Vue, etc.)\n- Complex multi-layered architecture for deep customization\n\n## Installation\n\n### NPM\n```bash\nnpm install overtype\n```\n\n### CDN\n```html\n\u003cscript src=\"https://unpkg.com/overtype/dist/overtype.min.js\"\u003e\u003c/script\u003e\n```\n\n## Quick Start\n\n```javascript\n// Create a single editor\nconst [editor] = new OverType('#editor', {\n  value: '# Hello World',\n  theme: 'solar'\n});\n\n// Get/set content\neditor.getValue();\neditor.setValue('# New Content');\n\n// Change theme\neditor.setTheme('cave');\n```\n\n## Usage\n\n### Basic Editor\n\n```html\n\u003cdiv id=\"editor\" style=\"height: 400px;\"\u003e\u003c/div\u003e\n\n\u003cscript\u003e\n  const [editor] = new OverType('#editor', {\n    placeholder: 'Start typing markdown...',\n    value: '# Welcome\\n\\nStart writing **markdown** here!',\n    onChange: (value, instance) =\u003e {\n      console.log('Content changed:', value);\n    }\n  });\n\u003c/script\u003e\n```\n\n### Toolbar \u0026 View Modes\n\n```javascript\n// Enable the toolbar with view mode switcher\nconst [editor] = new OverType('#editor', {\n  toolbar: true,  // Enables the toolbar\n  value: '# Document\\n\\nSelect text and use the toolbar buttons!'\n});\n\n// Toolbar provides:\n// - Bold, Italic formatting\n// - Heading levels (H1, H2, H3)\n// - Links, inline code, code blocks\n// - Bullet and numbered lists\n// - View mode switcher (eye icon dropdown)\n// - All with keyboard shortcuts!\n\n// Three view modes available via toolbar dropdown:\n// 1. Normal Edit - Default WYSIWYG markdown editing\n// 2. Plain Textarea - Shows raw markdown without preview overlay\n// 3. Preview Mode - Read-only rendered preview with clickable links\n\n// Programmatically switch modes:\neditor.showPlainTextarea(true);   // Switch to plain textarea mode\neditor.showPreviewMode(true);     // Switch to preview mode\n```\n\n### Keyboard Shortcuts\n\nThe toolbar and keyboard shortcuts work together seamlessly:\n\n- **Cmd/Ctrl + B** - Bold\n- **Cmd/Ctrl + I** - Italic\n- **Cmd/Ctrl + K** - Insert link\n- **Cmd/Ctrl + Shift + 7** - Numbered list\n- **Cmd/Ctrl + Shift + 8** - Bullet list\n\nAll shortcuts preserve text selection, allowing you to apply multiple formats quickly.\n\n### Multiple Editors\n\n```javascript\n// Initialize multiple editors at once\nconst editors = OverType.init('.markdown-editor', {\n  theme: 'cave',\n  fontSize: '16px'\n});\n\n// Each editor is independent\neditors.forEach((editor, index) =\u003e {\n  editor.setValue(`# Editor ${index + 1}`);\n});\n```\n\n### Form Integration\n\n```javascript\n// Use with form validation\nconst [editor] = new OverType('#message', {\n  placeholder: 'Your message...',\n  textareaProps: {\n    required: true,\n    maxLength: 500,\n    name: 'message'\n  }\n});\n\n// The textarea will work with native form validation\ndocument.querySelector('form').addEventListener('submit', (e) =\u003e {\n  const content = editor.getValue();\n  // Form will automatically validate required field\n});\n```\n\n### Custom Theme\n\n```javascript\nconst [editor] = new OverType('#editor', {\n  theme: {\n    name: 'my-theme',\n    colors: {\n      bgPrimary: '#faf0ca',\n      bgSecondary: '#ffffff',\n      text: '#0d3b66',\n      h1: '#f95738',\n      h2: '#ee964b',\n      h3: '#3d8a51',\n      strong: '#ee964b',\n      em: '#f95738',\n      link: '#0d3b66',\n      code: '#0d3b66',\n      codeBg: 'rgba(244, 211, 94, 0.2)',\n      blockquote: '#5a7a9b',\n      hr: '#5a7a9b',\n      syntaxMarker: 'rgba(13, 59, 102, 0.52)',\n      cursor: '#f95738',\n      selection: 'rgba(244, 211, 94, 0.4)'\n    }\n  }\n});\n```\n\n### Preview \u0026 HTML Export\n\nGenerate HTML previews or export the rendered content:\n\n```javascript\nconst [editor] = new OverType('#editor', {\n  value: '# Title\\n\\n**Bold** text with [links](https://example.com)'\n});\n\n// Get the raw markdown\nconst markdown = editor.getValue();\n// Returns: \"# Title\\n\\n**Bold** text with [links](https://example.com)\"\n\n// Get rendered HTML for display\nconst html = editor.getRenderedHTML();\n// Returns basic HTML with markdown elements\n\n// Get HTML with post-processing (consolidated lists/code blocks)\nconst processedHTML = editor.getRenderedHTML(true);\n// Returns HTML optimized for preview mode\n\n// Get the current preview element's HTML\nconst previewHTML = editor.getPreviewHTML();\n// Returns exactly what's shown in the editor's preview layer\n\n// Example: Create external preview\ndocument.getElementById('external-preview').innerHTML = editor.getRenderedHTML(true);\n```\n\n### Stats Bar\n\nEnable a built-in stats bar that shows character, word, and line counts:\n\n```javascript\n// Enable stats bar on initialization\nconst [editor] = new OverType('#editor', {\n  showStats: true\n});\n\n// Show or hide stats bar dynamically\neditor.showStats(true);  // Show\neditor.showStats(false); // Hide\n\n// Custom stats format\nconst [editor] = new OverType('#editor', {\n  showStats: true,\n  statsFormatter: (stats) =\u003e {\n    // stats object contains: { chars, words, lines, line, column }\n    return `\u003cspan\u003e${stats.chars} characters\u003c/span\u003e\n            \u003cspan\u003e${stats.words} words\u003c/span\u003e\n            \u003cspan\u003e${stats.lines} lines\u003c/span\u003e\n            \u003cspan\u003eLine ${stats.line}, Col ${stats.column}\u003c/span\u003e`;\n  }\n});\n```\n\nThe stats bar automatically adapts to your theme colors using CSS variables.\n\n### React Component\n\n```jsx\nfunction MarkdownEditor({ value, onChange }) {\n  const ref = useRef();\n  const editorRef = useRef();\n  \n  useEffect(() =\u003e {\n    const [instance] = OverType.init(ref.current, {\n      value,\n      onChange\n    });\n    editorRef.current = instance;\n    \n    return () =\u003e editorRef.current?.destroy();\n  }, []);\n  \n  useEffect(() =\u003e {\n    if (editorRef.current \u0026\u0026 value !== editorRef.current.getValue()) {\n      editorRef.current.setValue(value);\n    }\n  }, [value]);\n  \n  return \u003cdiv ref={ref} style={{ height: '400px' }} /\u003e;\n}\n```\n\n## API\n\n### Constructor\n\n```javascript\nnew OverType(target, options)\n```\n\n**Parameters:**\n- `target` - Selector string, Element, NodeList, or Array of elements\n- `options` - Configuration object (see below)\n\n**Returns:** Array of OverType instances (always an array, even for single element)\n\n### Options\n\n```javascript\n{\n  // Typography\n  fontSize: '14px',\n  lineHeight: 1.6,\n  fontFamily: 'monospace',\n  padding: '16px',\n  \n  // Theme - 'solar', 'cave', or custom theme object\n  theme: 'solar',\n  \n  // Custom colors (override theme colors)\n  colors: {\n    h1: '#e63946',\n    h2: '#457b9d',\n    // ... any color variable\n  },\n  \n  // Mobile styles (applied at \u003c= 640px)\n  mobile: {\n    fontSize: '16px',\n    padding: '12px',\n    lineHeight: 1.5\n  },\n  \n  // Behavior\n  autofocus: false,\n  placeholder: 'Start typing...',\n  value: '',\n  \n  // Auto-resize\n  autoResize: false,      // Auto-expand height with content\n  minHeight: '100px',     // Minimum height when autoResize is enabled\n  maxHeight: null,        // Maximum height (null = unlimited)\n  \n  // Native textarea properties\n  textareaProps: {\n    required: true,\n    maxLength: 500,\n    name: 'content',\n    // Any HTML textarea attribute\n  },\n  \n  // Toolbar\n  toolbar: false,         // Enable/disable toolbar with formatting buttons\n  \n  // Smart lists\n  smartLists: true,       // Enable GitHub-style list continuation on Enter\n  \n  // Stats bar\n  showStats: false,       // Enable/disable stats bar\n  statsFormatter: (stats) =\u003e {  // Custom stats format\n    return `${stats.chars} chars | ${stats.words} words`;\n  },\n  \n  // Callbacks\n  onChange: (value, instance) =\u003e {},\n  onKeydown: (event, instance) =\u003e {}\n}\n```\n\n### Instance Methods\n\n```javascript\n// Get current markdown content\neditor.getValue()\n\n// Set markdown content\neditor.setValue(markdown)\n\n// Get rendered HTML of the current content\neditor.getRenderedHTML()           // Basic HTML rendering\neditor.getRenderedHTML(true)       // With post-processing (consolidated lists/code blocks)\n\n// Get the current preview element's HTML\neditor.getPreviewHTML()            // Returns exactly what's displayed in the preview\n\n// Change theme\neditor.setTheme('cave')  // Built-in theme name\neditor.setTheme(customThemeObject)  // Custom theme\n\n// View modes\neditor.showPlainTextarea(true)    // Switch to plain textarea mode\neditor.showPlainTextarea(false)   // Switch back to normal mode\neditor.showPreviewMode(true)      // Switch to preview mode\neditor.showPreviewMode(false)     // Switch back to normal mode\n\n// Focus/blur\neditor.focus()\neditor.blur()\n\n// Show or hide stats bar\neditor.showStats(true)   // Show stats\neditor.showStats(false)  // Hide stats\n\n// Check if initialized\neditor.isInitialized()\n\n// Re-initialize with new options\neditor.reinit(options)\n\n// Destroy the editor\neditor.destroy()\n```\n\n### Static Methods\n\n```javascript\n// Set global theme (affects all instances)\nOverType.setTheme('cave')  // Built-in theme\nOverType.setTheme(customTheme)  // Custom theme object\nOverType.setTheme('solar', { h1: '#custom' })  // Override specific colors\n\n// Initialize multiple editors (same as constructor)\nOverType.init(target, options)\n\n// Get instance from element\nOverType.getInstance(element)\n\n// Destroy all instances\nOverType.destroyAll()\n\n// Access themes\nOverType.themes.solar\nOverType.themes.cave\n```\n\n## Keyboard Shortcuts\n\n| Shortcut | Action |\n|----------|--------|\n| Cmd/Ctrl + B | Toggle bold |\n| Cmd/Ctrl + I | Toggle italic |\n| Cmd/Ctrl + K | Wrap in code |\n| Cmd/Ctrl + Shift + K | Insert link |\n| Cmd/Ctrl + Shift + 7 | Toggle numbered list |\n| Cmd/Ctrl + Shift + 8 | Toggle bullet list |\n\n## Supported Markdown\n\n- **Headers** - `# H1`, `## H2`, `### H3`\n- **Bold** - `**text**` or `__text__`\n- **Italic** - `*text*` or `_text_`\n- **Code** - `` `inline code` ``\n- **Links** - `[text](url)`\n- **Lists** - `- item`, `* item`, `1. item`\n- **Blockquotes** - `\u003e quote`\n- **Horizontal rule** - `---`, `***`, or `___`\n\nNote: Markdown syntax remains visible but styled (e.g., `**bold**` shows with styled markers).\n\n## DOM Persistence \u0026 Re-initialization\n\nOverType is designed to work with platforms that persist DOM across page loads (like HyperClay):\n\n```javascript\n// Safe to call multiple times - will recover existing editors\nOverType.init('.editor');\n\n// The library will:\n// 1. Check for existing OverType DOM structure\n// 2. Recover content from existing textarea if found\n// 3. Re-establish event bindings\n// 4. Or create fresh editor if no existing DOM\n```\n\n## Examples\n\nCheck the `examples` folder for complete examples:\n\n- `basic.html` - Simple single editor\n- `multiple.html` - Multiple independent editors\n- `custom-theme.html` - Theme customization\n- `dynamic.html` - Dynamic creation/destruction\n\n## Limitations\n\nDue to the transparent textarea overlay approach, OverType has some intentional design limitations:\n\n### Images Not Supported\nImages (`![alt](url)`) are not rendered. Variable-height images would break the character alignment between textarea and preview.\n\n### Monospace Font Required\nAll text must use a monospace font to maintain alignment. Variable-width fonts would cause the textarea cursor position to drift from the visual text position.\n\n### Fixed Font Size\nAll content must use the same font size. Different sizes for headers or other elements would break vertical alignment.\n\n### Visible Markdown Syntax\nAll markdown formatting characters remain visible (e.g., `**bold**` shows the asterisks). This is intentional - hiding them would break the 1:1 character mapping.\n\n### Links Require Modifier Key\nLinks are clickable with Cmd/Ctrl+Click only. Direct clicking would interfere with text editing since clicks need to position the cursor in the textarea.\n\nThese limitations are what enable OverType's core benefits: perfect native textarea behavior, tiny size, and zero complexity.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Development build with watch\nnpm run dev\n\n# Production build\nnpm run build\n\n# Run tests\nnpm test\n\n# Check bundle size\nnpm run size\n```\n\n## Browser Support\n\n- Chrome 62+\n- Firefox 78+\n- Safari 16+\n- Edge (Chromium)\n\nRequires support for:\n- CSS Custom Properties\n- ES6 features\n- Lookbehind assertions in RegExp (for italic parsing)\n\n## Architecture\n\nOverType uses a unique invisible textarea overlay approach:\n\n1. **Two perfectly aligned layers:**\n   - Invisible textarea (top) - handles input and cursor\n   - Styled preview div (bottom) - shows formatted markdown\n\n2. **Character-perfect alignment:**\n   - Monospace font required\n   - No size changes in styling\n   - Syntax markers remain visible\n\n3. **Single source of truth:**\n   - Textarea content drives everything\n   - One-way data flow: textarea → parser → preview\n\n## Contributors\n\nSpecial thanks to:\n- [Josh Doman](https://github.com/joshdoman) - Fixed inline code formatting preservation ([#6](https://github.com/panphora/overtype/pull/6)), improved code fence detection ([#19](https://github.com/panphora/overtype/pull/19))\n- [kbhomes](https://github.com/kbhomes) - Fixed text selection desynchronization during overscroll ([#17](https://github.com/panphora/overtype/pull/17))\n- [merlinz01](https://github.com/merlinz01) - Initial TypeScript definitions implementation ([#20](https://github.com/panphora/overtype/pull/20))\n- [Max Bernstein](https://github.com/tekknolagi) - Fixed typo in website ([#11](https://github.com/panphora/overtype/pull/11))\n- [davidlazar](https://github.com/davidlazar) - Suggested view mode feature for toggling overlay and preview modes ([#24](https://github.com/panphora/overtype/issues/24))\n\n## License\n\nMIT\n\n## Related Projects\n\n### Synesthesia\n\n[Synesthesia](https://github.com/panphora/synesthesia) is a lightweight syntax highlighting editor library that extracted and refined the core textarea overlay technique from OverType. While OverType is focused on markdown editing with toolbar features, Synesthesia provides a more generalized code editing solution with:\n\n- **Pluggable parser system** - Support for any programming language or syntax\n- **Parser registry** - Automatic language detection by file extension or MIME type  \n- **Cleaner separation** - Extracted the overlay technique without markdown-specific features\n- **Smaller footprint** - ~82KB minified (vs OverType's ~78KB)\n\nKey components extracted from OverType to Synesthesia:\n- The transparent textarea overlay technique for perfect WYSIWYG alignment\n- Theme system with CSS variable support\n- DOM persistence and recovery mechanisms  \n- Auto-resize functionality\n- Event delegation for efficient multi-instance support\n\nIf you need a markdown editor with toolbar and formatting features, use OverType. If you need a lightweight code editor with custom syntax highlighting, check out Synesthesia.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n---\n\nReady for another radical idea?  \n[Let's remove every layer of the web application stack.](https://hyperclay.com)\n","funding_links":[],"categories":["JavaScript","编码与开发工具"],"sub_categories":["开发组件"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanphora%2Fovertype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpanphora%2Fovertype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanphora%2Fovertype/lists"}